home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.1_SDK_DR3 / Source / VDig / FWCCMDriver / FWCCMDriver.c next >
Encoding:
C/C++ Source or Header  |  1999-05-17  |  131.6 KB  |  4,453 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWCCMDriver.c
  3.  
  4.     Contains:    Driver software for CCM cameras implemented as a video
  5.                 digitizer component.
  6.  
  7.     Written by:    Erik Staats
  8.  
  9.     Copyright:    © 1996-1997 by Apple Computer, Inc., all rights reserved.
  10.  
  11.     Change History (most recent first):
  12.  
  13.       <FW33>     8/15/97    EA        Changed to skip frames when CPU is saturated.
  14.       <FW32>      6/5/97    EA        Unified the three DCL programs into one, with variable
  15.                                     callProcs. Unified the three colorspace conversion routines,
  16.                                     then made the result modular by target depth. Changed DCL design
  17.                                     to use hardware to skip frames we can't accept, to eliminate
  18.                                     fruitless callProcs, eliminate most mangled frames, and support
  19.                                     Pele (where we don't see sync in running DMA). Considerably
  20.                                     improved record (async grab) performance in some cases.
  21.       <FW31>     3/18/97    ES        Changed driver description version to final.
  22.       <FW31>     3/18/97    ES        Changed driver description version to final.
  23.       <FW30>     2/20/97    ES        Changed to use plug in dispatch table.
  24.       <FW29>     1/16/97    ES        Added use of DCLUpdateList commands.
  25.       <FW28>    12/27/96    ES        Changed FWCCMOpen to set csrRegBaseEntryID invalid at the
  26.                                     beginning.
  27.       <FW27>    12/27/96    ES        Changed a bunch of "FWDriver"s to "FWClient"s.
  28.       <FW26>    12/22/96    ES        Changed IsochPortAction to IsochPortControl.
  29.       <FW25>    12/10/96    ES        Removed early reset notification and added isoch channel
  30.                                     forceful stop notification.
  31.       <FW24>     12/4/96    ES        Fixed crashing bug when isochronous resources cannot be
  32.                                     allocated.
  33.       <FW23>    10/24/96    ES        Changed to work with Component Driver expert.
  34.       <FW22>    10/16/96    ES        Added bus management notification proc to improve hot
  35.                                     plugability.
  36.       <FW21>     9/27/96    ES        Changed to use set driver interface calls rather than driver
  37.                                     interface table.
  38.       <FW20>     9/26/96    ES        Fixed problem with timeout in FWCCMGrabOneFrame.
  39.       <FW19>     9/16/96    ES        Changed FireWire driver interface procs to return command
  40.                                     acceptance.
  41.       <FW18>      9/4/96    ES        Added more deallocation.
  42.       <FW17>      9/3/96    ES        Added reset notification handling. Will restart active
  43.                                     isochronous channel on resets.
  44.       <FW16>     8/29/96    ES        Changed FWRegisterDriver to take driver interface proc table.
  45.       <FW15>     8/28/96    ES        Changed the way trial works in InitIsochPort and fixed setting
  46.                                     of isoch channel number in camera.
  47.       <FW14>     8/26/96    ES        Changed to new command object interface.
  48.       <FW13>     8/26/96    ES        Changed some constant names.
  49.       <FW12>     8/16/96    ES        Changed FWAllocateLocalIsochronousPort to take param block. Made
  50.                                     some other minor modifications.
  51.       <FW11>     8/15/96    ES        Updated for changes to isochronous mechanisms.
  52.       <FW10>      8/2/96    ES        Updated for more isochronous changes.
  53.        <FW9>      8/2/96    ES        Updated to work with QuickTimeComponents.h from ETO #21.
  54.        <FW8>      8/1/96    ES        Took out unused local variables.
  55.        <FW7>     7/31/96    ES        Changed to use new isochronous buffer architecture.
  56.        <FW6>      7/8/96    ES        Changed call to FWAllocateIsochronousChannelID to set IRM
  57.                                     allocation to true.
  58.        <FW5>     6/28/96    ES        Changed to use DebugStrStatus instead of DebugStr.
  59.        <FW4>     6/27/96    ES        Took out include of AdminMessagePort.h.
  60.        <FW3>     6/20/96    ES        Changed so we can build with MrC.
  61.        <FW2>     6/20/96    ES        Filled in contains and written by fields.
  62.        <FW1>     6/20/96    ES        first checked in
  63.  
  64. */
  65.  
  66. #include <Types.h>
  67. #include <Errors.h>
  68. #include <Devices.h>
  69. #include <MixedMode.h>
  70. #include <DriverServices.h>
  71. #include <FireWire.h>
  72. #include <Components.h>
  73. #include <QuickTimeComponents.h>
  74. #include <FWCCMDriver.h>
  75. /*zzz*/
  76. #include <stdio.h>
  77. char  debugStr[256];
  78. /*zzz*/
  79. //zzz Use descriptions out of documentation for standard vdig procs comments.
  80. //zzz need some register defs.
  81.  
  82.  
  83. //////////////////////////////////////////////////////////////////////////////
  84. //
  85. //  ## Some items not currently implemented ##
  86. //
  87. //  We could use more optimized aligned (and double) writes in some cases
  88. //  during the colorspace conversion.
  89. //
  90. //  We could use a higher-quality colorspace conversion.
  91. //
  92. //  We could support the 640x480 4:1:1 YUV mode (200 mbps required).
  93. //
  94. //  We could display blue when there is no signal, using timeouts.
  95. //
  96. //  It would be nice during playthrough to sync with the vertical refresh
  97. //  in order to avoid tearing the image.
  98. //
  99. //  Could add a non-optimized colorspace conversion routine that handles all
  100. //  frame rates.  The lower frame rates are sometimes helpful in debugging.
  101. //
  102. //////////////////////////////////////////////////////////////////////////////
  103.  
  104.  
  105. /*zzz should be in a system header file*/
  106. enum
  107. {
  108.     kComponentDriverPluginVersion        = 0x00010000
  109. };
  110.  
  111. typedef pascal ComponentResult    (ComponentDriverInitializeProc) (
  112.     RegEntryIDPtr                pRegEntryID);
  113. typedef ComponentDriverInitializeProc
  114.                                 *ComponentDriverInitializeProcPtr;
  115.  
  116. typedef pascal ComponentResult    (ComponentDriverFinalizeProc) (
  117.     RegEntryIDPtr                pRegEntryID);
  118. typedef ComponentDriverFinalizeProc
  119.                                 *ComponentDriverFinalizeProcPtr;
  120.  
  121. struct ComponentDriverPluginDispatchTableStruct
  122. {
  123.     UInt32                                pluginVersion;
  124.     ComponentDriverInitializeProcPtr    componentDriverInitializeProc;        // Proc that initializes the component driver.
  125.     ComponentDriverFinalizeProcPtr        componentDriverFinalizeProc;        // Proc that finalizes the component driver.
  126.     ComponentRoutineProcPtr                componentInterfaceProcPtr;            // Proc that polls for interrupts.
  127. };
  128. typedef struct ComponentDriverPluginDispatchTableStruct
  129.                                 ComponentDriverPluginDispatchTable,
  130.                                 *ComponentDriverPluginDispatchTablePtr;
  131. /*zzz*/
  132.  
  133. ////////////////////////////////////////////////////////////////////////////////
  134. //
  135. // Internal procedure prototypes.
  136. //
  137.  
  138. static OSStatus    FWCCMBusManagementNotify (
  139.     FWClientInterfaceParamsPtr    pFWClientInterfaceParams,
  140.     UInt32                        *pCommandAcceptance);
  141.  
  142. static void    FWResetNotifyRestartChannelCompletionProc1 (
  143.     FWCommandObjectID            fwCommandObjectID,
  144.     OSStatus                    commandStatus,
  145.     UInt32                        completionProcData);
  146.  
  147. static void    FWResetNotifyRestartChannelCompletionProc2 (
  148.     FWCommandObjectID            fwCommandObjectID,
  149.     OSStatus                    commandStatus,
  150.     UInt32                        completionProcData);
  151.  
  152. static OSStatus    FWCCMInitIsochPort (
  153.     FWClientInitIsochPortParamsPtr
  154.                                 pInitIsochPortParams,
  155.     UInt32                        *pCommandAcceptance);
  156.  
  157. static OSStatus    FWCCMReleaseIsochPort (
  158.     FWClientReleaseIsochPortParamsPtr
  159.                                 pReleaseIsochPortParams,
  160.     UInt32                        *pCommandAcceptance);
  161.  
  162. static OSStatus    FWCCMStartIsochPort (
  163.     FWClientIsochPortControlParamsPtr
  164.                                 pIsochPortControlParams,
  165.     UInt32                        *pCommandAcceptance);
  166.  
  167. static OSStatus    FWCCMStopIsochPort (
  168.     FWClientIsochPortControlParamsPtr
  169.                                 pIsochPortControlParams,
  170.     UInt32                        *pCommandAcceptance);
  171.  
  172. static OSStatus    FWCCMIsochChannelForceStopNotification (
  173.     IsochChannelID                isochChannelID,
  174.     UInt32                        stopCondition);
  175.  
  176. pascal ComponentResult    ComponentInterface (
  177.     ComponentParameters            *pComponentParams,
  178.     Handle                        componentSpecificData);
  179.  
  180. static pascal ComponentResult    FWCCMOpen (
  181.     Handle                        componentSpecificData,
  182.     ComponentOpenParamsPtr        pComponentOpenParams);
  183.  
  184. static void FWCCMWriteDCLProgram(
  185.     FWCCMVDigDataPtr            pFWCCMVDigData);
  186.  
  187. static void FWCCMSetupDCLProgram(
  188.     FWCCMVDigDataPtr            pFWCCMVDigData,
  189.     DCLCallCommandProcPtr        callProc);
  190.  
  191. static void FWCCMSetDCLProgramEndFrame(
  192.     FWCCMVDigDataPtr            pFWCCMVDigData,
  193.     UInt32                        endFrameNum);
  194.  
  195. static pascal ComponentResult    FWCCMClose (
  196.     Handle                        componentSpecificData,
  197.     ComponentCloseParamsPtr        pComponentCloseParams);
  198.  
  199. static pascal ComponentResult    FWCCMVersion (
  200.     Handle                        componentSpecificData);
  201.  
  202. static pascal ComponentResult    FWCCMInitializeDriver (
  203.     RegEntryIDPtr                pRegEntryID);
  204.  
  205. static pascal ComponentResult    FWCCMFinalizeDriver (
  206.     RegEntryIDPtr                pRegEntryID);
  207.  
  208. static pascal VideoDigitizerError    FWCCMGetActiveSrcRect (
  209.     Handle                        componentSpecificData,
  210.     VDigGetActiveSrcRectParamsPtr
  211.                                 pVDigGetActiveSrcRectParams);
  212.  
  213. static pascal VideoDigitizerError    FWCCMSetDigitizerRect (
  214.     Handle                        componentSpecificData,
  215.     VDigSetDigitizerRectParamsPtr
  216.                                 pVDigSetDigitizerRectParams);
  217.  
  218. static pascal VideoDigitizerError    FWCCMGetDigitizerInfo (
  219.     Handle                        componentSpecificData,
  220.     VDigGetDigitizerInfoParamsPtr
  221.                                 pVDigGetDigitizerInfoParams);
  222.  
  223. static pascal VideoDigitizerError    FWCCMGetCurrentFlags (
  224.     Handle                        componentSpecificData,
  225.     VDigGetCurrentFlagsParamsPtr
  226.                                 pVDigGetCurrentFlagsParams);
  227.  
  228. static pascal VideoDigitizerError    FWCCMSetPlayThruDestination (
  229.     Handle                        componentSpecificData,
  230.     VDigSetPlayThruDestinationParamsPtr
  231.                                 pVDigSetPlayThruDestinationParams);
  232.  
  233. static pascal VideoDigitizerError    FWCCMSetPlayThruOnOff (
  234.     Handle                        componentSpecificData,
  235.     VDigSetPlayThruOnOffParamsPtr
  236.                                 pVDigSetPlayThruOnOffParams);
  237.  
  238. static pascal VideoDigitizerError    FWCCMSetHue (
  239.     Handle                        componentSpecificData,
  240.     VDigSetHueParamsPtr            pVDigSetHueParams);
  241.  
  242. static pascal VideoDigitizerError    FWCCMSetSaturation (
  243.     Handle                        componentSpecificData,
  244.     VDigSetSaturationParamsPtr    pVDigSetSaturationParams);
  245.  
  246. static pascal VideoDigitizerError    FWCCMGetHue (
  247.     Handle                        componentSpecificData,
  248.     VDigGetHueParamsPtr            pVDigGetHueParams);
  249.  
  250. static pascal VideoDigitizerError    FWCCMGetSaturation (
  251.     Handle                        componentSpecificData,
  252.     VDigGetSaturationParamsPtr    pVDigGetSaturationParams);
  253.  
  254. static pascal VideoDigitizerError    FWCCMGrabOneFrame (
  255.     Handle                        componentSpecificData);
  256.  
  257. static pascal VideoDigitizerError    FWCCMPreflightDestination (
  258.     Handle                        componentSpecificData,
  259.     VDigPreflightDestinationParamsPtr
  260.                                 pVDigPreflightDestinationParams);
  261.  
  262. static pascal VideoDigitizerError    FWCCMSetBlackLevelValue (
  263.     Handle                        componentSpecificData,
  264.     VDigSetBlackLevelValueParamsPtr
  265.                                 pVDigSetBlackLevelValueParams);
  266.  
  267. static pascal VideoDigitizerError    FWCCMGetBlackLevelValue (
  268.     Handle                        componentSpecificData,
  269.     VDigGetBlackLevelValueParamsPtr
  270.                                 pVdigGetBlackLevelValueParams);
  271.  
  272. static pascal VideoDigitizerError    FWCCMSetWhiteLevelValue (
  273.     Handle                        componentSpecificData,
  274.     VDigSetWhiteLevelValueParamsPtr
  275.                                 pVDigSetWhiteLevelValueParams);
  276.  
  277. static pascal VideoDigitizerError    FWCCMGetWhiteLevelValue (
  278.     Handle                        componentSpecificData,
  279.     VDigGetWhiteLevelValueParamsPtr
  280.                                 pVDigGetWhiteLevelValueParams);
  281.  
  282. static pascal VideoDigitizerError    FWCCMGetNumberOfInputs (
  283.     Handle                        componentSpecificData,
  284.     VDigGetNumberOfInputsParamsPtr
  285.                                 pVDigGetNumberOfInputsParams);
  286.  
  287. static pascal VideoDigitizerError    FWCCMGetInput (
  288.     Handle                        componentSpecificData,
  289.     VDigGetInputParamsPtr        pVDigGetInputParams);
  290.  
  291. static pascal VideoDigitizerError    FWCCMSetInputStandard (
  292.     Handle                        componentSpecificData,
  293.     VDigSetInputStandardParamsPtr
  294.                                 pVDigSetInputStandardParams);
  295.  
  296. static pascal VideoDigitizerError    FWCCMSetupBuffers (
  297.     Handle                        componentSpecificData,
  298.     VDigSetupBuffersParamsPtr    pVDigSetupBuffersParams);
  299.  
  300. static pascal VideoDigitizerError    FWCCMGrabOneFrameAsync (
  301.     Handle                        componentSpecificData,
  302.     VDigGrabOneFrameAsyncParamsPtr
  303.                                 pVDigGrabOneFrameAsyncParams);
  304.  
  305. static pascal long    FWCCMDone (
  306.     Handle                        componentSpecificData,
  307.     VDigDoneParamsPtr            pVDigDoneParams);
  308.  
  309. static pascal VideoDigitizerError    FWCCMSetFrameRate (
  310.     Handle                        componentSpecificData,
  311.     VDigSetFrameRateParamsPtr    pVDigSetFrameRateParams);
  312.  
  313. static pascal VideoDigitizerError    FWCCMReleaseAsyncBuffers (
  314.     Handle                        componentSpecificData);
  315.  
  316. static void    FWCCMCopyToDestPixMap (
  317.     FWCCMVDigDataPtr            pFWCCMVDigData);
  318.  
  319. static void    FWCCMAsyncGrabIsochHandler (
  320.     DCLCommandPtr                pDCLCommandPtr);
  321.  
  322. static void    FWCCMCopyIsochChannelToVdigBuffer (
  323.     FWCCMVDigDataPtr            pFWCCMVDigData,
  324.     DCLTransferPacketPtr        pDCLTransferPacket,
  325.     VdigBufferRecQElemPtr        pVdigBufferRecQElem);
  326.  
  327. static void    FWCCMPlayThruIsochHandler (
  328.     DCLCommandPtr                pDCLCommandPtr);
  329.  
  330. static void    FWCCMGrabOneFrameIsochHandler (
  331.     DCLCommandPtr                pDCLCommandPtr);
  332.  
  333. static void    FWCCMCopyIsochChannelToDestPixMap (
  334.     FWCCMVDigDataPtr            pFWCCMVDigData,
  335.     DCLTransferPacketPtr        pDCLTransferPacket);
  336.  
  337. static void    FWCCMConvertYUV422ToRGB16(
  338.     FWCCMVDigDataPtr            pFWCCMVDigData,
  339.     UInt32                        *pSrcYUV,
  340.     UInt32                        byteCountYUV,
  341.     UInt32                        *pDstRGB,
  342.     UInt32                        rowBytesRGB);
  343.  
  344. static void    FWCCMConvertYUV422ToRGB16Double(
  345.     FWCCMVDigDataPtr            pFWCCMVDigData,
  346.     UInt32                        *pSrcYUV,
  347.     UInt32                        byteCountYUV,
  348.     UInt32                        *pDstRGB,
  349.     UInt32                        rowBytesRGB);
  350.  
  351. static void    FWCCMConvertYUV422ToRGB32(
  352.     FWCCMVDigDataPtr            pFWCCMVDigData,
  353.     UInt32                        *pSrcYUV,
  354.     UInt32                        byteCountYUV,
  355.     UInt32                        *pDstRGB,
  356.     UInt32                        rowBytesRGB);
  357.  
  358. static void    FWCCMConvertYUV422ToRGB32Double(
  359.     FWCCMVDigDataPtr            pFWCCMVDigData,
  360.     UInt32                        *pSrcYUV,
  361.     UInt32                        byteCountYUV,
  362.     UInt32                        *pDstRGB,
  363.     UInt32                        rowBytesRGB);
  364.  
  365. static void    FWCCMDelayForHardware (
  366.     Duration                    duration);
  367.  
  368. static void    FWCCMClientCommandCompletionProc (
  369.     FWCommandObjectID            fwCommandObjectID,
  370.     OSStatus                    commandStatus,
  371.     UInt32                        completionProcData);
  372.  
  373.  
  374. ////////////////////////////////////////////////////////////////////////////////
  375. //
  376. // The driver descriptor.
  377. //
  378.  
  379. DriverDescription                 TheDriverDescription =
  380. {
  381.     kTheDescriptionSignature,
  382.     kInitialDriverDescriptor,
  383.     {
  384.         "\pfwa02d,100",
  385.         1, 0, finalStage, 1,
  386.     },
  387.     {
  388.         kDriverIsUnderExpertControl,
  389.         "\pFWCCMDriver",
  390.     },
  391.  
  392.     1,
  393.     'comp',
  394.     'vdig',
  395.     1,0,0,0
  396. };
  397.  
  398.  
  399. ////////////////////////////////////////////////////////////////////////////////
  400. //
  401. // The plug in dispatch table.
  402. //
  403.  
  404. ComponentDriverPluginDispatchTable
  405.                                 ThePluginDispatchTable =
  406. {
  407.     kComponentDriverPluginVersion,
  408.     FWCCMInitializeDriver,
  409.     FWCCMFinalizeDriver,
  410.     ComponentInterface
  411. };
  412.  
  413.  
  414. ////////////////////////////////////////////////////////////////////////////////
  415. //
  416. // Global driver data.
  417. //
  418.  
  419. FWCCMDriverDataPtr                gpFWCCMDriverData = nil;
  420.  
  421.  
  422. ////////////////////////////////////////////////////////////////////////////////
  423. //
  424. // FWCCMTerminate
  425. //
  426. //   This proc terminates the FireWire CCM driver.
  427. //
  428.  
  429. long    FWCCMTerminate()
  430. {
  431.     OSStatus                    status = noErr;
  432.  
  433.     // Dispose of FWCCM data.
  434.     if (gpFWCCMDriverData != nil)
  435.     {
  436.         PoolDeallocate ((Ptr) gpFWCCMDriverData);
  437.         gpFWCCMDriverData = nil;
  438.     }
  439.  
  440.     return status;
  441. }
  442.  
  443.  
  444. ////////////////////////////////////////////////////////////////////////////////
  445. //
  446. // FWCCMBusManagementNotify
  447. //
  448. //   This routine handles reset notification when bus management has been
  449. // established.  If ISO_EN is set before the cycle master is enabled, ISO_EN
  450. // will get cleared with the cycle master begins sending cycle start packets.
  451. // Thus, we need this routine to execute after the bus manager has enabled
  452. // the cycle master.
  453. //zzz this routine should check if ISO_EN has been cleared before doing
  454. //zzz anything.
  455. //zzz maybe this routine just needs to set ISO_EN instead of doing a full
  456. //zzz stop and start.
  457. //
  458.  
  459. static OSStatus    FWCCMBusManagementNotify(
  460.     FWClientInterfaceParamsPtr    pFWClientInterfaceParams,
  461.     UInt32                        *pCommandAcceptance)
  462. {
  463.     FWCCMDriverDataPtr            pFWCCMDriverData;
  464.     FWCCMVDigDataPtr            pFWCCMVDigData;
  465.     FWCommandObjectID            isochChannelCommandObjectID;
  466.     OSStatus                    status = noErr;
  467.  
  468.     // Get our driver data.
  469.     pFWCCMDriverData = (FWCCMDriverDataPtr) pFWClientInterfaceParams->fwClientSpecificData;
  470.     pFWCCMVDigData = pFWCCMDriverData->pFWCCMVDigData;
  471.  
  472.     // Restart isochronous channel if it should be active.
  473.     if ((pFWCCMVDigData->channelActive) &&
  474.         (!(pFWCCMVDigData->startStopIsochChannelCommandObjectsInUse)))
  475.     {
  476.         // Command objects now in use.
  477.         pFWCCMVDigData->startStopIsochChannelCommandObjectsInUse = true;
  478.  
  479.         // Stop channel.
  480.         isochChannelCommandObjectID = pFWCCMVDigData->stopIsochChannelCommandObjectID;
  481.         FWSetFWCommandParams (isochChannelCommandObjectID,
  482.                               kInvalidFWReferenceID,
  483.                               0,
  484.                               FWResetNotifyRestartChannelCompletionProc1,
  485.                               (UInt32) pFWCCMVDigData);
  486.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  487.                                                 pFWCCMVDigData->isochChannelID);
  488.         pFWCCMVDigData->channelActive = false;
  489.         FWStopIsochronousChannel (isochChannelCommandObjectID);
  490.     }
  491.  
  492.     // Complete FireWire client command.
  493.     FWClientCommandIsComplete (pFWClientInterfaceParams->fwClientCommandID, status);
  494.  
  495.     // Return command acceptance.
  496.     //zzz is this the right way?  If we've completed the command, we can accept more.
  497.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  498.  
  499.     return status;
  500. }
  501.  
  502.  
  503. ////////////////////////////////////////////////////////////////////////////////
  504. //
  505. // FWResetNotifyRestartChannelCompletionProc1
  506. //
  507. //   This routine will issue a start isoch channel command after a stop isoch
  508. // channel command has completed.
  509. //
  510.  
  511. static void    FWResetNotifyRestartChannelCompletionProc1(
  512.     FWCommandObjectID            fwCommandObjectID,
  513.     OSStatus                    commandStatus,
  514.     UInt32                        completionProcData)
  515. {
  516.     FWCCMVDigDataPtr            pFWCCMVDigData;
  517.     FWCommandObjectID            isochChannelCommandObjectID;
  518.  
  519.     // Get VDig data from completionProcData.
  520.     pFWCCMVDigData = (FWCCMVDigDataPtr) completionProcData;
  521.  
  522.     // Start channel.
  523.     isochChannelCommandObjectID = pFWCCMVDigData->startIsochChannelCommandObjectID;
  524.     FWSetFWCommandParams
  525.         (isochChannelCommandObjectID,
  526.          kInvalidFWReferenceID,
  527.          0,
  528.          FWResetNotifyRestartChannelCompletionProc2,
  529.          (UInt32) &(pFWCCMVDigData->startStopIsochChannelCommandObjectsInUse));
  530.     FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  531.                                             pFWCCMVDigData->isochChannelID);
  532.     pFWCCMVDigData->channelActive = true;
  533.     FWStartIsochronousChannel (isochChannelCommandObjectID);
  534. }
  535.  
  536.  
  537. ////////////////////////////////////////////////////////////////////////////////
  538. //
  539. // FWResetNotifyRestartChannelCompletionProc2
  540. //
  541. //   This routine will release a lock on the start and stop isoch channel
  542. // command object.  A pointer to the lock is provided in the completionProcData.
  543. //
  544.  
  545. static void    FWResetNotifyRestartChannelCompletionProc2(
  546.     FWCommandObjectID            fwCommandObjectID,
  547.     OSStatus                    commandStatus,
  548.     UInt32                        completionProcData)
  549. {
  550.     UInt32                        *pStartStopIsochChannelCommandObjectsInUse;
  551.  
  552.     // Clear lock on start/stop command objects.
  553.     pStartStopIsochChannelCommandObjectsInUse = (UInt32 *) completionProcData;
  554.     *pStartStopIsochChannelCommandObjectsInUse = false;
  555. }
  556.  
  557.  
  558. ////////////////////////////////////////////////////////////////////////////////
  559. //
  560. // FWCCMInitIsochPort
  561. //
  562. //   This routine initializes an isochronous port for the FireWire CCM camera.
  563. // If the request is for the talking port, this routine sets up the camera's
  564. // isochronous port.  If the request is for the listening port, this routine
  565. // sets up the local node's isochronous port.
  566. //zzz should have resolution/frame-rate in ref con and program it
  567. //
  568.  
  569. static OSStatus    FWCCMInitIsochPort(
  570.     FWClientInitIsochPortParamsPtr
  571.                                 pInitIsochPortParams,
  572.     UInt32                        *pCommandAcceptance)
  573. {
  574.     FWCCMDriverDataPtr            pFWCCMDriverData;
  575.     FWCCMVDigDataPtr            pFWCCMVDigData;
  576.     FWCommandObjectID            isochPortCommandObjectID;
  577.     FWCommandObjectID            asynchCommandObjectID;
  578.     UInt32                        channelNum;
  579.     UInt32                        speed;
  580.     Boolean                        portIsTalker;
  581.     Boolean                        trial;
  582.     UInt32                        fwCCMReg;
  583.     OSStatus                    status = noErr;
  584.  
  585. //    DebugStr ((ConstStr255Param) "\pFWCCMInitIsochPort");
  586.  
  587.     // Get our driver data.
  588.     pFWCCMDriverData = (FWCCMDriverDataPtr)
  589.         pInitIsochPortParams->fwClientInterfaceParams.fwClientSpecificData;
  590.  
  591.     // Get our VDig data from refCon.
  592.     pFWCCMVDigData = (FWCCMVDigDataPtr) pInitIsochPortParams->fwClientIsochPortParams.refCon;
  593.  
  594.     // Get speed and channel number.
  595.     speed = pInitIsochPortParams->speed;
  596.     channelNum = pInitIsochPortParams->channelNum;
  597.  
  598.     // Is this request for the talking port?
  599.     portIsTalker = pInitIsochPortParams->fwClientIsochPortParams.portIsTalker;
  600.  
  601.     // Is this a trial?
  602.     trial = pInitIsochPortParams->trial;
  603.  
  604.     // Initialize.
  605.     if (portIsTalker)
  606.     {
  607.         // Port is for camera.
  608.         if (!trial)
  609.         {
  610.             // Check params.
  611.             if ((speed > kFWSpeed100MBit) || (channelNum > 15))
  612.                 status = paramErr;
  613.  
  614.             // Program camera for given channel number.
  615.             if (status == noErr)
  616.             {
  617.                 fwCCMReg = channelNum << 28;
  618.                 asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  619.                 FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  620.                                                 0x0000FFFF,
  621.                                                 pFWCCMDriverData->regBaseAddress + 0x060C,
  622.                                                 (Ptr) &fwCCMReg,
  623.                                                 4);
  624.  
  625.                 FWCCMDelayForHardware (100*durationMillisecond);
  626.                 status = FWWrite (asynchCommandObjectID);
  627.             }
  628.         }
  629.         else
  630.         {
  631.             // Return supported channel numbers.
  632.             pInitIsochPortParams->supportedChannelNumHi = 0xFFFF0000;
  633.             pInitIsochPortParams->supportedChannelNumLo = 0x00000000;
  634.  
  635.             // Return supported speed.
  636.             if (speed > kFWSpeed100MBit)
  637.                 pInitIsochPortParams->speed = kFWSpeed100MBit;
  638.         }
  639.     }
  640.     else
  641.     {
  642.         // Port is for local node.
  643.         if (!trial)
  644.         {
  645.             // Allocate an isoch port ID.
  646.             status = FWAllocateIsochPortID (&(pFWCCMVDigData->isochPortID),
  647.                                             pFWCCMVDigData->dclProgramID,
  648.                                             channelNum,
  649.                                             speed,
  650.                                             portIsTalker);
  651.  
  652.             // Send an allocate isoch port command to allocate port for listening.
  653.             if (status == noErr)
  654.             {
  655.                 // Set up command object.
  656.                 isochPortCommandObjectID = pFWCCMVDigData->isochPortCommandObjectID;
  657.                 FWSetFWCommandParams (isochPortCommandObjectID,
  658.                                       (FWReferenceID) pFWCCMDriverData->fwDriverID,
  659.                                       kFWCommandSyncFlag,
  660.                                       nil,
  661.                                       0);
  662.                 FWSetIsochPortCommandIsochPortID (isochPortCommandObjectID,
  663.                                                   pFWCCMVDigData->isochPortID);
  664.  
  665.                 // Send command
  666.                 status = FWAllocateLocalIsochronousPort (isochPortCommandObjectID);
  667.             }
  668.         }
  669.         else
  670.         {
  671.             // Return supported channel numbers.
  672.             pInitIsochPortParams->supportedChannelNumHi = 0xFFFF0000;
  673.             pInitIsochPortParams->supportedChannelNumLo = 0x00000000;
  674.  
  675.             // Return supported speed.
  676.             if (speed > kFWSpeed100MBit)
  677.                 pInitIsochPortParams->speed = kFWSpeed100MBit;
  678.         }
  679.     }
  680.  
  681.     // Complete FireWire client command.
  682.     FWClientCommandIsComplete
  683.         (pInitIsochPortParams->fwClientInterfaceParams.fwClientCommandID, status);
  684.  
  685.     // Return command acceptance.
  686.     //zzz is this the right way?  If we've completed the command, we can accept more.
  687.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  688.  
  689.     return status;
  690. }
  691.  
  692.  
  693. ////////////////////////////////////////////////////////////////////////////////
  694. //
  695. // FWCCMReleaseIsochPort
  696. //
  697. //   This procedure releases resources allocated for the isochronous channel.
  698. // If the channel is a listener, this routine will release the local
  699. // isochronous port.
  700. //
  701.  
  702. static OSStatus    FWCCMReleaseIsochPort(
  703.     FWClientReleaseIsochPortParamsPtr
  704.                                 pReleaseIsochPortParams,
  705.     UInt32                        *pCommandAcceptance)
  706. {
  707.     FWCCMDriverDataPtr            pFWCCMDriverData;
  708.     FWCCMVDigDataPtr            pFWCCMVDigData;
  709.     FWCommandObjectID            isochPortCommandObjectID;
  710.     Boolean                        portIsTalker;
  711.     OSStatus                    status = noErr;
  712.  
  713. //    DebugStr ((ConstStr255Param) "\pFWCCMReleaseIsochPort");
  714.  
  715.     // Get our driver data.
  716.     pFWCCMDriverData = (FWCCMDriverDataPtr)
  717.         pReleaseIsochPortParams->fwClientInterfaceParams.fwClientSpecificData;
  718.  
  719.     // Get our VDig data from refCon.
  720.     pFWCCMVDigData = (FWCCMVDigDataPtr)
  721.         pReleaseIsochPortParams->fwClientIsochPortParams.refCon;
  722.  
  723.     // Is this request for the talking port?
  724.     portIsTalker = pReleaseIsochPortParams->fwClientIsochPortParams.portIsTalker;
  725.  
  726.     if (!portIsTalker)
  727.     {
  728.         // Set up command object to release port.
  729.         isochPortCommandObjectID = pFWCCMVDigData->isochPortCommandObjectID;
  730.         FWSetFWCommandParams (isochPortCommandObjectID,
  731.                               (FWReferenceID) pFWCCMDriverData->fwDriverID,
  732.                               kFWCommandSyncFlag,
  733.                               nil,
  734.                               0);
  735.         FWSetIsochPortCommandIsochPortID
  736.             (isochPortCommandObjectID, pFWCCMVDigData->isochPortID);
  737.  
  738.         FWReleaseLocalIsochronousPort (isochPortCommandObjectID);
  739.  
  740.         // Deallocate isoch port ID.
  741.         FWDeallocateIsochPortID (pFWCCMVDigData->isochPortID);
  742.     }
  743.  
  744.     // Complete FireWire client command.
  745.     FWClientCommandIsComplete
  746.         (pReleaseIsochPortParams->fwClientInterfaceParams.fwClientCommandID, status);
  747.  
  748.     // Return command acceptance.
  749.     //zzz is this the right way?  If we've completed the command, we can accept more.
  750.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  751.  
  752.     return status;
  753. }
  754.  
  755.  
  756. ////////////////////////////////////////////////////////////////////////////////
  757. //
  758. // FWCCMStartIsochPort
  759. //
  760. //   This procedure starts the isochronous channel.  If the channel is a
  761. // talker, this procedure will program the camera to start sending isochronous
  762. // data.  If the channel is a listener, this procedure will start the local
  763. // isochronous port.
  764. //
  765.  
  766. static OSStatus    FWCCMStartIsochPort(
  767.     FWClientIsochPortControlParamsPtr
  768.                                 pIsochPortControlParams,
  769.     UInt32                        *pCommandAcceptance)
  770. {
  771.     FWCCMDriverDataPtr            pFWCCMDriverData;
  772.     FWCCMVDigDataPtr            pFWCCMVDigData;
  773.     FWCommandObjectID            asynchCommandObjectID;
  774.     FWCommandObjectID            isochPortCommandObjectID;
  775.     Boolean                        portIsTalker;
  776.     UInt32                        *pFWCCMReg;
  777.     OSStatus                    status = noErr;
  778.  
  779. //    DebugStr ((ConstStr255Param) "\pFWCCMStartIsochPort");
  780.  
  781.     // Get our driver data.
  782.     pFWCCMDriverData = (FWCCMDriverDataPtr)
  783.         pIsochPortControlParams->fwClientInterfaceParams.fwClientSpecificData;
  784.  
  785.     // Get our VDig data from refCon.
  786.     pFWCCMVDigData = (FWCCMVDigDataPtr) pIsochPortControlParams->fwClientIsochPortParams.refCon;
  787.  
  788.     // Is this request for the talking port?
  789.     portIsTalker = pIsochPortControlParams->fwClientIsochPortParams.portIsTalker;
  790.  
  791.     if (portIsTalker)
  792.     {
  793.         // Send an async write packet to ISO_EN register.
  794.         pFWCCMReg = &(pFWCCMVDigData->fwCCMReg);
  795.         *pFWCCMReg = 0x80000000;
  796.         asynchCommandObjectID = pFWCCMVDigData->startAsynchCommandObjectID;
  797.         FWSetFWCommandCompletionProcData
  798.             (asynchCommandObjectID,
  799.              (UInt32) pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID);
  800.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  801.                                         0x0000FFFF,
  802.                                         pFWCCMDriverData->regBaseAddress + 0x0614,
  803.                                         (Ptr) pFWCCMReg,
  804.                                         4);
  805.  
  806.         // Write register.
  807.         FWCCMDelayForHardware (100*durationMillisecond);
  808.         status = FWWrite (asynchCommandObjectID);
  809.     }
  810.     else
  811.     {
  812.         // Set up command object to start port.
  813.         isochPortCommandObjectID = pFWCCMVDigData->isochPortCommandObjectID;
  814.         FWSetFWCommandParams
  815.             (isochPortCommandObjectID,
  816.              (FWReferenceID) pFWCCMDriverData->fwDriverID,
  817.              0,
  818.              FWCCMClientCommandCompletionProc,
  819.              (UInt32) pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID);
  820.         FWSetIsochPortCommandIsochPortID (isochPortCommandObjectID,
  821.                                           pFWCCMVDigData->isochPortID);
  822.  
  823.         // Send command to start port.
  824.         status = FWStartLocalIsochronousPort (isochPortCommandObjectID);
  825.     }
  826.  
  827.     // Return command acceptance.
  828.     //zzz is this the right way?  If we've completed the command, we can accept more.
  829.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  830.  
  831.     return status;
  832. }
  833.  
  834.  
  835. ////////////////////////////////////////////////////////////////////////////////
  836. //
  837. // FWCCMStopIsochPort
  838. //
  839. //   This procedure stops the isochronous channel.  If the channel is a
  840. // talker, this procedure will program the camera to stop sending isochronous
  841. // data.  If the channel is a listener, this procedure will stop the local
  842. // isochronous port.
  843. //
  844.  
  845. static OSStatus    FWCCMStopIsochPort(
  846.     FWClientIsochPortControlParamsPtr
  847.                                 pIsochPortControlParams,
  848.     UInt32                        *pCommandAcceptance)
  849. {
  850.     FWCCMDriverDataPtr            pFWCCMDriverData;
  851.     FWCCMVDigDataPtr            pFWCCMVDigData;
  852.     FWCommandObjectID            asynchCommandObjectID;
  853.     FWCommandObjectID            isochPortCommandObjectID;
  854.     Boolean                        portIsTalker;
  855.     UInt32                        *pFWCCMReg;
  856.     OSStatus                    status = noErr;
  857.  
  858. //    DebugStr ((ConstStr255Param) "\pFWCCMStopIsochPort");
  859.  
  860.     // Get our driver data.
  861.     pFWCCMDriverData = (FWCCMDriverDataPtr)
  862.         pIsochPortControlParams->fwClientInterfaceParams.fwClientSpecificData;
  863.  
  864.     // Get our VDig data from refCon.
  865.     pFWCCMVDigData = (FWCCMVDigDataPtr) pIsochPortControlParams->fwClientIsochPortParams.refCon;
  866.  
  867.     // Is this request for the talking port?
  868.     portIsTalker = pIsochPortControlParams->fwClientIsochPortParams.portIsTalker;
  869.  
  870.     if (portIsTalker)
  871.     {
  872.         // Send an async write packet to ISO_EN register.
  873.         pFWCCMReg = &(pFWCCMVDigData->fwCCMReg);
  874.         *pFWCCMReg = 0x00000000;
  875.         asynchCommandObjectID = pFWCCMVDigData->stopAsynchCommandObjectID;
  876.         FWSetFWCommandCompletionProcData
  877.             (asynchCommandObjectID,
  878.              (UInt32) pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID);
  879.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  880.                                         0x0000FFFF,
  881.                                         pFWCCMDriverData->regBaseAddress + 0x0614,
  882.                                         (Ptr) pFWCCMReg,
  883.                                         4);
  884.  
  885.         // Write register.
  886.         FWCCMDelayForHardware (100*durationMillisecond);
  887.         status = FWWrite (asynchCommandObjectID);
  888.     }
  889.     else
  890.     {
  891.         // Set up command object to stop port.
  892.         isochPortCommandObjectID = pFWCCMVDigData->isochPortCommandObjectID;
  893.         FWSetFWCommandParams
  894.             (isochPortCommandObjectID,
  895.              (FWReferenceID) pFWCCMDriverData->fwDriverID,
  896.              0,
  897.              FWCCMClientCommandCompletionProc,
  898.              (UInt32) pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID);
  899.         FWSetIsochPortCommandIsochPortID
  900.             (isochPortCommandObjectID, pFWCCMVDigData->isochPortID);
  901.  
  902.         // Send command to stop port.
  903.         status = FWStopLocalIsochronousPort (isochPortCommandObjectID);
  904.     }
  905.  
  906.     // Return command acceptance.
  907.     //zzz is this the right way?  If we've completed the command, we can accept more.
  908.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  909.  
  910.     return status;
  911. }
  912.  
  913.  
  914. ////////////////////////////////////////////////////////////////////////////////
  915. //
  916. // FWCCMIsochChannelForceStopNotification
  917. //
  918. //   This routine is called when the isochronous channel is forcefully stopped.
  919. //
  920.  
  921. static OSStatus    FWCCMIsochChannelForceStopNotification(
  922.     IsochChannelID                isochChannelID,
  923.     UInt32                        stopCondition)
  924. {
  925.     OSStatus                    status = noErr;
  926.  
  927.     return status;
  928. }
  929.  
  930.  
  931. ////////////////////////////////////////////////////////////////////////////////
  932. //
  933. // ComponentInterface
  934. //
  935. //   Main entry point for FireWire CCM VDig component.
  936. //
  937.  
  938. pascal ComponentResult    ComponentInterface(
  939.     ComponentParameters            *pComponentParams,
  940.     Handle                        componentSpecificData)
  941. {
  942.     ComponentResult                result = noErr;
  943.  
  944.     // Create a routine descriptor based on interface selector.
  945.     switch (pComponentParams->what)
  946.     {
  947.         case kComponentOpenSelect :
  948.             result = FWCCMOpen
  949.                         (componentSpecificData,
  950.                          (ComponentOpenParamsPtr) pComponentParams->params);
  951.             break;
  952.  
  953.         case kComponentCloseSelect :
  954.             result = FWCCMClose
  955.                         (componentSpecificData,
  956.                          (ComponentCloseParamsPtr) pComponentParams->params);
  957.             break;
  958.  
  959.         case kComponentCanDoSelect :
  960.             /*zzz*/
  961.             DebugStrStatus ((ConstStr255Param) "\pComponentCanDo");
  962.             result = -1;
  963.             /*zzz*/
  964.             break;
  965.  
  966.         case kComponentVersionSelect :
  967.             result = FWCCMVersion (componentSpecificData);
  968.             break;
  969.  
  970.         case kComponentTargetSelect :
  971.             /*zzz*/
  972.             DebugStrStatus ((ConstStr255Param) "\pComponentTargetSelect");
  973.             result = -1;
  974.             /*zzz*/
  975.             break;
  976.  
  977.         case kComponentRegisterSelect :
  978.             /*zzz*/
  979.             DebugStrStatus ((ConstStr255Param) "\pComponentRegisterSelect");
  980.             result = -1;
  981.             /*zzz*/
  982.             break;
  983.  
  984.         case kVDGetActiveSrcRectSelect :
  985.             result = FWCCMGetActiveSrcRect
  986.                         (componentSpecificData,
  987.                          (VDigGetActiveSrcRectParamsPtr) pComponentParams->params);
  988.             break;
  989.  
  990.         case kVDSetDigitizerRectSelect :
  991.             result = FWCCMSetDigitizerRect
  992.                         (componentSpecificData,
  993.                          (VDigSetDigitizerRectParamsPtr) pComponentParams->params);
  994.             break;
  995.  
  996.         case kVDSetHueSelect :
  997.             result = FWCCMSetHue
  998.                         (componentSpecificData,
  999.                          (VDigSetHueParamsPtr) pComponentParams->params);
  1000.             break;
  1001.  
  1002.         case kVDSetSaturationSelect :
  1003.             result = FWCCMSetSaturation
  1004.                         (componentSpecificData,
  1005.                          (VDigSetSaturationParamsPtr) pComponentParams->params);
  1006.             break;
  1007.  
  1008.         case kVDGetHueSelect :
  1009.             result = FWCCMGetHue
  1010.                         (componentSpecificData,
  1011.                          (VDigGetHueParamsPtr) pComponentParams->params);
  1012.             break;
  1013.  
  1014.         case kVDGetSaturationSelect :
  1015.             result = FWCCMGetSaturation
  1016.                         (componentSpecificData,
  1017.                          (VDigGetSaturationParamsPtr) pComponentParams->params);
  1018.             break;
  1019.  
  1020.         case kVDGrabOneFrameSelect :
  1021.             result = FWCCMGrabOneFrame (componentSpecificData);
  1022.             break;
  1023.  
  1024.         case kVDGetDigitizerInfoSelect :
  1025.             result = FWCCMGetDigitizerInfo
  1026.                         (componentSpecificData,
  1027.                          (VDigGetDigitizerInfoParamsPtr) pComponentParams->params);
  1028.             break;
  1029.  
  1030.         case kVDGetCurrentFlagsSelect :
  1031.             result = FWCCMGetCurrentFlags
  1032.                         (componentSpecificData,
  1033.                          (VDigGetCurrentFlagsParamsPtr) pComponentParams->params);
  1034.             break;
  1035.  
  1036.         case kVDSetPlayThruDestinationSelect :
  1037.             result = FWCCMSetPlayThruDestination
  1038.                         (componentSpecificData,
  1039.                          (VDigSetPlayThruDestinationParamsPtr) pComponentParams->params);
  1040.             break;
  1041.  
  1042.         case kVDSetPlayThruOnOffSelect :
  1043.             result = FWCCMSetPlayThruOnOff
  1044.                         (componentSpecificData,
  1045.                          (VDigSetPlayThruOnOffParamsPtr) pComponentParams->params);
  1046.             break;
  1047.  
  1048.         case kVDPreflightDestinationSelect :
  1049.             result = FWCCMPreflightDestination
  1050.                         (componentSpecificData,
  1051.                          (VDigPreflightDestinationParamsPtr) pComponentParams->params);
  1052.             break;
  1053.  
  1054.         case kVDSetBlackLevelValueSelect :
  1055.             result = FWCCMSetBlackLevelValue
  1056.                         (componentSpecificData,
  1057.                          (VDigSetBlackLevelValueParamsPtr) pComponentParams->params);
  1058.             break;
  1059.  
  1060.         case kVDGetBlackLevelValueSelect :
  1061.             result = FWCCMGetBlackLevelValue
  1062.                         (componentSpecificData,
  1063.                          (VDigGetBlackLevelValueParamsPtr) pComponentParams->params);
  1064.             break;
  1065.  
  1066.         case kVDSetWhiteLevelValueSelect :
  1067.             result = FWCCMSetWhiteLevelValue
  1068.                         (componentSpecificData,
  1069.                          (VDigSetWhiteLevelValueParamsPtr) pComponentParams->params);
  1070.             break;
  1071.  
  1072.         case kVDGetWhiteLevelValueSelect :
  1073.             result = FWCCMGetWhiteLevelValue
  1074.                         (componentSpecificData,
  1075.                          (VDigGetWhiteLevelValueParamsPtr) pComponentParams->params);
  1076.             break;
  1077.  
  1078.         case kVDGetNumberOfInputsSelect :
  1079.             result = FWCCMGetNumberOfInputs
  1080.                         (componentSpecificData,
  1081.                          (VDigGetNumberOfInputsParamsPtr) pComponentParams->params);
  1082.             break;
  1083.  
  1084.         case kVDGetInputSelect :
  1085.             result = FWCCMGetInput
  1086.                         (componentSpecificData,
  1087.                          (VDigGetInputParamsPtr) pComponentParams->params);
  1088.             break;
  1089.  
  1090.         case kVDSetInputStandardSelect :
  1091.             result = FWCCMSetInputStandard
  1092.                         (componentSpecificData,
  1093.                          (VDigSetInputStandardParamsPtr) pComponentParams->params);
  1094.             break;
  1095.  
  1096.         case kVDSetupBuffersSelect :
  1097. /*zzz*/
  1098.     DebugStrStatus ((ConstStr255Param) "\pSetup buffers");
  1099. /*zzz*/
  1100.             result = FWCCMSetupBuffers
  1101.                         (componentSpecificData,
  1102.                          (VDigSetupBuffersParamsPtr) pComponentParams->params);
  1103.             break;
  1104.  
  1105.         case kVDGrabOneFrameAsyncSelect :
  1106.             result = FWCCMGrabOneFrameAsync
  1107.                         (componentSpecificData,
  1108.                          (VDigGrabOneFrameAsyncParamsPtr) pComponentParams->params);
  1109.             break;
  1110.  
  1111.         case kVDDoneSelect :
  1112.             result = FWCCMDone
  1113.                         (componentSpecificData,
  1114.                          (VDigDoneParamsPtr) pComponentParams->params);
  1115.             break;
  1116.  
  1117.         case kVDSetFrameRateSelect :
  1118.             result = FWCCMSetFrameRate
  1119.                         (componentSpecificData,
  1120.                          (VDigSetFrameRateParamsPtr) pComponentParams->params);
  1121.             break;
  1122.  
  1123.         case kVDReleaseAsyncBuffersSelect :
  1124.             result = FWCCMReleaseAsyncBuffers (componentSpecificData);
  1125.             break;
  1126.  
  1127.         case kVDGetFieldPreferenceSelect :
  1128.             /*zzz*/
  1129.             DebugStrStatus ((ConstStr255Param) "\pkVDGetFieldPreferenceSelect");
  1130.             result = -1;
  1131.             /*zzz*/
  1132.             break;
  1133.  
  1134.         case kVDGetInputFormatSelect :
  1135.             /*zzz*/
  1136.             DebugStrStatus ((ConstStr255Param) "\pkVDGetInputFormatSelect");
  1137.             result = -1;
  1138.             /*zzz*/
  1139.             break;
  1140.  
  1141.         case kVDGetVBlankRectSelect :
  1142.             /*zzz*/
  1143.             DebugStrStatus ((ConstStr255Param) "\pkVDGetVBlankRectSelect");
  1144.             result = -1;
  1145.             /*zzz*/
  1146.             break;
  1147.  
  1148.         case kVDSetInputSelect :
  1149.             /*zzz*/
  1150.             DebugStrStatus ((ConstStr255Param) "\pkVDSetInputSelect");
  1151.             result = -1;
  1152.             /*zzz*/
  1153.             break;
  1154.  
  1155.         case kVDGetDigitizerRectSelect :
  1156.             /*zzz*/
  1157.             DebugStrStatus ((ConstStr255Param) "\pkVDGetDigitizerRectSelect");
  1158.             result = -1;
  1159.             /*zzz*/
  1160.             break;
  1161.  
  1162.         case kVDGetMaxSrcRectSelect :
  1163.             /*zzz*/
  1164.             DebugStrStatus ((ConstStr255Param) "\pkVDGetMaxSrcRectSelect");
  1165.             result = -1;
  1166.             /*zzz*/
  1167.             break;
  1168.  
  1169.         case kVDGetPlayThruDestinationSelect :
  1170.             /*zzz*/
  1171.             DebugStrStatus ((ConstStr255Param) "\pkVDGetPlayThruDestinationSelect");
  1172.             result = -1;
  1173.             /*zzz*/
  1174.             break;
  1175.  
  1176.         case kVDGetVideoDefaultsSelect :
  1177.             /*zzz*/
  1178.             DebugStrStatus ((ConstStr255Param) "\pkVDGetVideoDefaultsSelect");
  1179.             result = -1;
  1180.             /*zzz*/
  1181.             break;
  1182.  
  1183.         case kVDSetFieldPreferenceSelect :
  1184.             /*zzz*/
  1185.             DebugStrStatus ((ConstStr255Param) "\pkVDSetFieldPreferenceSelect");
  1186.             result = -1;
  1187.             /*zzz*/
  1188.             break;
  1189.  
  1190.         default :
  1191.             /*zzz*/
  1192.             //zzzsprintf (DebugStrStatus, "Unknown selector %lx", (long) pComponentParams->what);
  1193.             //zzzDebugStrStatus ((ConstStr255Param) c2pstr (DebugStrStatus));
  1194.             /*zzz*/
  1195.             result = digiUnimpErr;//zzz is this right for all calls???
  1196.             break;
  1197.     }
  1198.  
  1199.     return result;
  1200. }
  1201.  
  1202.  
  1203. ////////////////////////////////////////////////////////////////////////////////
  1204. //
  1205. // FWCCMOpen
  1206. //
  1207. //   Open routine for FireWire CCM VDig component.
  1208. //
  1209.  
  1210. static pascal ComponentResult    FWCCMOpen(
  1211.     Handle                        componentSpecificData,
  1212.     ComponentOpenParamsPtr        pComponentOpenParams)
  1213. {
  1214.     FWCCMDriverDataPtr            pFWCCMDriverData;
  1215.     FWCCMVDigDataPtr            pFWCCMVDigData;
  1216.     Handle                        fwCCMVDigDataHandle = nil;
  1217.     CSRROMEntryIterator            csrROMIterator = kInvalidCSRROMIterator;
  1218.     CSRROMEntryID                csrRegBaseEntryID = kInvalidCSRROMEntryID;
  1219.     CSRROMSearchCriteria        searchCriteria;
  1220.     Ptr                            frameBuf;
  1221.     UInt16                        *yuvToRGB16Table;
  1222.     UInt32                        *yuvToRGB32Table;
  1223.     FWCommandObjectID            asynchCommandObjectID;
  1224.     IsochChannelID                isochChannelID;
  1225.     DCLCommandPtr                dclList;
  1226.     DCLCommandPtr                *updateDCLList;
  1227.     UInt32                        fwCCMReg;
  1228.     UInt8                        Y, uU, uV;
  1229.     SInt8                        U, V;
  1230.     SInt32                        R, G, B;
  1231.     UInt32                        yuv;
  1232.     Boolean                        done;
  1233.     CSRNodeUniqueID             uniqueID;
  1234.     UInt32                        beta3yuvEncoding;
  1235.     UInt32                        i;
  1236.     ComponentResult                result = noErr;
  1237. /*zzz*/
  1238.     DebugStrStatus ((ConstStr255Param) "\pComponentOpen");
  1239. /*zzz*/
  1240.  
  1241.     // We can only have one owner at a time.
  1242.     if (CountComponentInstances ((Component) pComponentOpenParams->componentInstance) > 1)
  1243.         result = -1;//zzz is there something better?
  1244.  
  1245.     // Get driver data.
  1246.     pFWCCMDriverData = gpFWCCMDriverData;
  1247.  
  1248.     // Allocate VDig data.
  1249.     if (result == noErr)
  1250.     {
  1251.         fwCCMVDigDataHandle = NewHandleClear (sizeof (FWCCMVDigData));
  1252.         if (fwCCMVDigDataHandle != nil)
  1253.         {
  1254.             MoveHHi (fwCCMVDigDataHandle);
  1255.             HLock (fwCCMVDigDataHandle);
  1256.             pFWCCMVDigData = (FWCCMVDigDataPtr) *fwCCMVDigDataHandle;
  1257.             pFWCCMDriverData->pFWCCMVDigData = pFWCCMVDigData;
  1258.         }
  1259.         else
  1260.         {
  1261.             result = memFullErr;
  1262.         }
  1263.     }
  1264.  
  1265.     ////////////////////////////////////////////////////////////////////////////
  1266.     //
  1267.     // Get register file base address offset.
  1268.     //
  1269.  
  1270.     // Create a CSR ROM search iterator.
  1271.     if (result == noErr)
  1272.     {
  1273.         result = FWCSRROMCreateIterator
  1274.                     (&csrROMIterator,
  1275.                      (FWReferenceID) pFWCCMDriverData->fwDriverID);
  1276.     }
  1277.  
  1278.     // Set iterator to start searching at our unit directory.
  1279.     if (result == noErr)
  1280.     {
  1281.         result = FWCSRROMSetIterator
  1282.                     (csrROMIterator,
  1283.                      pFWCCMDriverData->csrUnitID,
  1284.                      kIterateDescendants);
  1285.     }
  1286.  
  1287.     // Search for register base address offset entry.
  1288.     if (result == noErr)
  1289.     {
  1290.         searchCriteria.csrROMSearchType = kCSRROMSearchForKey;
  1291.         searchCriteria.keyType = kCSROffsetKeyTypeBit;
  1292.         searchCriteria.keyHi = 0;
  1293.         searchCriteria.keyLo = (1 << 0);//zzz need def here
  1294.         result = FWCSRROMEntrySearch (csrROMIterator,
  1295.                                       kIterateContinue,
  1296.                                       &csrRegBaseEntryID,
  1297.                                       &done,
  1298.                                       &searchCriteria,
  1299.                                       nil,
  1300.                                       nil);
  1301.  
  1302.         if (done)
  1303.             result = notFoundErr;//zzz what should we really do?
  1304.     }
  1305.  
  1306.     // Register base address is address of register base address offset data.
  1307.     if (result == noErr)
  1308.     {
  1309.         result = FWCSRROMGetEntryDataAddress
  1310.                     (csrRegBaseEntryID, &(pFWCCMDriverData->regBaseAddress));
  1311.     }
  1312.  
  1313.     // Clean up.
  1314.     if (csrROMIterator != kInvalidCSRROMIterator)
  1315.         FWCSRROMDisposeIterator (csrROMIterator);
  1316.     if (csrRegBaseEntryID != kInvalidCSRROMEntryID)
  1317.         FWCSRROMDisposeEntryID (csrRegBaseEntryID);
  1318.  
  1319.     // Create a queue for async grabs.
  1320.     if (result == noErr)
  1321.         result = PBQueueCreate(&(pFWCCMVDigData->vdigBufferRecQueue));
  1322.  
  1323.     // Create a DCL program.
  1324.     if (result == noErr)
  1325.         result = FWCreateDCLProgram (&(pFWCCMVDigData->dclProgramID));
  1326.  
  1327.     // Create list of DCLs.
  1328.     if (result == noErr)
  1329.     {
  1330.         dclList = (DCLCommandPtr) PoolAllocateResident (kDCLProgramSize, false);
  1331.         pFWCCMVDigData->dclList = dclList;
  1332.         if (!dclList)
  1333.             result = memFullErr;
  1334.     }
  1335.  
  1336.     // Create DCL update list.
  1337.     if (result == noErr)
  1338.     {
  1339.         updateDCLList = (DCLCommandPtr *)
  1340.             PoolAllocateResident (kNumTransferDCLs * sizeof (DCLCommandPtr), false);
  1341.         pFWCCMVDigData->updateDCLList = updateDCLList;
  1342.         if (!updateDCLList)
  1343.             result = memFullErr;
  1344.     }
  1345.  
  1346.     // Check "Unique" ID to see which YUV format to use.
  1347.     // All Beta 3 cameras have 0xFFFFFFFF for the low 32-bits of their unique
  1348.     // ID.
  1349.     if (result == noErr)
  1350.     {
  1351.         result = FWGetUniqueID ((FWReferenceID) pFWCCMDriverData->fwDriverID,
  1352.                                 &uniqueID);
  1353.  
  1354.         if (result == noErr)
  1355.         {
  1356.             if (uniqueID.lo == 0xFFFFFFFF)
  1357.                 beta3yuvEncoding = true;
  1358.             else
  1359.                 beta3yuvEncoding = false;
  1360.         }
  1361.     }
  1362.  
  1363.     // Allocate frame buffers.
  1364.     if (result == noErr)
  1365.     {
  1366.         for (i = 0; i < kNumFrameBufs; i++)
  1367.         {
  1368.             if (result == noErr)
  1369.             {
  1370.                 frameBuf = PoolAllocateResident (kFrameBufSize, false);
  1371.                 pFWCCMVDigData->frameBuf[i] = frameBuf;
  1372.                 if (!frameBuf)
  1373.                     result = memFullErr;
  1374.             }
  1375.         }
  1376.  
  1377.         // Clean up if we ran out of memory
  1378.         if (result == memFullErr)
  1379.         {
  1380.             for (i = 0; i < kNumFrameBufs; i++)
  1381.                 if (pFWCCMVDigData->frameBuf[i])
  1382.                     PoolDeallocate ((Ptr) pFWCCMVDigData->frameBuf[i]);
  1383.         }
  1384.     }
  1385.  
  1386.     // Write general-purpose DCL program.
  1387.     if (result == noErr)
  1388.     {
  1389.         FWCCMWriteDCLProgram (pFWCCMVDigData);
  1390.     }
  1391.  
  1392.     // Allocate and fill in YUV to RGB conversion table.
  1393.     // Create 16-bit 6:5:5 YUV to 32-bit RGB table.
  1394.     if (result == noErr)
  1395.     {
  1396.         yuvToRGB16Table =
  1397.             (UInt16 *) PoolAllocateResident ((1 << 16) * sizeof (UInt16), false);
  1398.         if (yuvToRGB16Table)
  1399.         {
  1400.             yuvToRGB32Table =
  1401.                 (UInt32 *) PoolAllocateResident ((1 << 16) * sizeof (UInt32), false);
  1402.             if (yuvToRGB32Table)
  1403.             {
  1404.                 pFWCCMVDigData->yuvToRGB16Table = yuvToRGB16Table;
  1405.                 pFWCCMVDigData->yuvToRGB32Table = yuvToRGB32Table;
  1406.                 for (yuv = 0; yuv < 0x10000; yuv++)
  1407.                 {
  1408.                     // Get YUV components from index.
  1409.                     Y = (yuv >> 8) & 0x00FC;
  1410.                     uU = (yuv >> 2) & 0x00F8;
  1411.                     U = beta3yuvEncoding ?
  1412.                         (SInt8) uU :
  1413.                         (SInt8) (((int) uU) - 128);
  1414.                     uV = (yuv << 3) & 0x00F8;
  1415.                     V = beta3yuvEncoding ?
  1416.                         (SInt8) uV :
  1417.                         (SInt8) (((int) uV) - 128);
  1418.     
  1419.                     // Compute RGB components from YUV components.
  1420.                     R = Y + 1.398*V;
  1421.                     G = Y - 0.3456*U - 0.7126*V;
  1422.                     B = Y + 1.778*U;
  1423.     
  1424.                     // Apply thresholding to RGB components.
  1425.                     if (R > 255)
  1426.                         R = 255;
  1427.                     if (R < 0)
  1428.                         R = 0;
  1429.                     if (G > 255)
  1430.                         G = 255;
  1431.                     if (G < 0)
  1432.                         G = 0;
  1433.                     if (B > 255)
  1434.                         B = 255;
  1435.                     if (B < 0)
  1436.                         B = 0;
  1437.     
  1438.                     // Fill in table.
  1439.                     yuvToRGB16Table[yuv] = ((R & 0xf8) << 7) |
  1440.                                            ((G & 0xf8) << 2) |
  1441.                                            ((B & 0xf8) >> 3);        // (& is useless)
  1442.                     yuvToRGB32Table[yuv] = (R << 16) | (G << 8) | B;
  1443.                 }
  1444.             }
  1445.             else
  1446.             {
  1447.                 PoolDeallocate ((Ptr) yuvToRGB16Table);
  1448.                 result = memFullErr;
  1449.             }
  1450.         }
  1451.         else
  1452.         {
  1453.             result = memFullErr;
  1454.         }
  1455.     }
  1456.  
  1457.     // Allocate an isochronous channel to receive video data.
  1458.     if (result == noErr)
  1459.     {
  1460.         result = FWAllocateIsochronousChannelID
  1461.                     (&isochChannelID, true, 10000000, kFWSpeed100MBit);
  1462.  
  1463.         if (result == noErr)
  1464.             pFWCCMVDigData->isochChannelID = isochChannelID;
  1465.     }
  1466.  
  1467.     // Set forceful stop notification procedure.
  1468.     if (result == noErr)
  1469.     {
  1470.         result = FWSetIsochChannelForceStopNotificationProc
  1471.                     (isochChannelID, FWCCMIsochChannelForceStopNotification);
  1472.     }
  1473.  
  1474.     // Add camera as talking client.
  1475.     if (result == noErr)
  1476.     {
  1477.         result = FWAddIsochronousChannelClient
  1478.                     (pFWCCMVDigData->isochChannelID,
  1479.                      pFWCCMDriverData->fwDriverID,
  1480.                      (UInt32) pFWCCMVDigData,
  1481.                      true);
  1482.     }
  1483.  
  1484.     // Add local node as listening client.
  1485.     if (result == noErr)
  1486.     {
  1487.         result = FWAddIsochronousChannelClient
  1488.                     (pFWCCMVDigData->isochChannelID,
  1489.                      pFWCCMDriverData->fwDriverID,
  1490.                      (UInt32) pFWCCMVDigData,
  1491.                      false);
  1492.     }
  1493.  
  1494.     // Allocate FireWire command object for sending asynchronous packets.
  1495.     if (result == noErr)
  1496.     {
  1497.         result = FWAllocateAsynchCommandObject (&asynchCommandObjectID);
  1498.         if (result == noErr)
  1499.             pFWCCMVDigData->asynchCommandObjectID = asynchCommandObjectID;
  1500.     }
  1501.  
  1502.     // Set up FireWire command object for sending asynchronous packets.
  1503.     if (result == noErr)
  1504.     {
  1505.         FWSetFWCommandParams (asynchCommandObjectID,
  1506.                               (FWReferenceID) pFWCCMDriverData->fwDriverID,
  1507.                               kFWCommandSyncFlag,
  1508.                               nil,
  1509.                               0);
  1510.         FWSetAsynchCommandMaxRetries (asynchCommandObjectID, 8);
  1511.     }
  1512.  
  1513.     // Allocate FireWire command object for sending camera start asynchronous packets.
  1514.     if (result == noErr)
  1515.     {
  1516.         result = FWAllocateAsynchCommandObject (&asynchCommandObjectID);
  1517.         if (result == noErr)
  1518.             pFWCCMVDigData->startAsynchCommandObjectID = asynchCommandObjectID;
  1519.     }
  1520.  
  1521.     // Set up FireWire command object for sending camera start asynchronous packets.
  1522.     if (result == noErr)
  1523.     {
  1524.         FWSetFWCommandParams (asynchCommandObjectID,
  1525.                               (FWReferenceID) pFWCCMDriverData->fwDriverID,
  1526.                               0,
  1527.                               FWCCMClientCommandCompletionProc,
  1528.                               0);
  1529.         FWSetAsynchCommandMaxRetries (asynchCommandObjectID, 8);
  1530.     }
  1531.  
  1532.     // Allocate FireWire command object for sending camera stop asynchronous packets.
  1533.     if (result == noErr)
  1534.     {
  1535.         result = FWAllocateAsynchCommandObject (&asynchCommandObjectID);
  1536.         if (result == noErr)
  1537.             pFWCCMVDigData->stopAsynchCommandObjectID = asynchCommandObjectID;
  1538.     }
  1539.  
  1540.     // Set up FireWire command object for sending camera stop asynchronous packets.
  1541.     if (result == noErr)
  1542.     {
  1543.         FWSetFWCommandParams (asynchCommandObjectID,
  1544.                               (FWReferenceID) pFWCCMDriverData->fwDriverID,
  1545.                               0,
  1546.                               FWCCMClientCommandCompletionProc,
  1547.                               0);
  1548.         FWSetAsynchCommandMaxRetries (asynchCommandObjectID, 8);
  1549.     }
  1550.  
  1551.     // Allocate FireWire command object for sending isoch channel commands.
  1552.     if (result == noErr)
  1553.     {
  1554.         result = FWAllocateIsochChannelCommandObject
  1555.                     (&(pFWCCMVDigData->isochChannelCommandObjectID));
  1556.     }
  1557.  
  1558.     // Allocate FireWire command object for sending asynchronous start isoch channel commands.
  1559.     if (result == noErr)
  1560.     {
  1561.         result = FWAllocateIsochChannelCommandObject
  1562.                     (&(pFWCCMVDigData->startIsochChannelCommandObjectID));
  1563.     }
  1564.  
  1565.     // Allocate FireWire command object for sending asynchronous stop isoch channel commands.
  1566.     if (result == noErr)
  1567.     {
  1568.         result = FWAllocateIsochChannelCommandObject
  1569.                     (&(pFWCCMVDigData->stopIsochChannelCommandObjectID));
  1570.     }
  1571.  
  1572.     // Allocate FireWire command object for sending isoch port commands
  1573.     // synchronously.
  1574.     if (result == noErr)
  1575.     {
  1576.         result = FWAllocateIsochPortCommandObject
  1577.                     (&(pFWCCMVDigData->isochPortCommandObjectID));
  1578.     }
  1579.  
  1580.     // Set camera to 30 fps.
  1581.     if (result == noErr)
  1582.     {
  1583.         fwCCMReg = 0x80000000;
  1584.         asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  1585.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  1586.                                         0x0000FFFF,
  1587.                                         pFWCCMDriverData->regBaseAddress + 0x0600,
  1588.                                         (Ptr) &fwCCMReg,
  1589.                                         4);
  1590.  
  1591.         FWCCMDelayForHardware (100*durationMillisecond);
  1592.         result = FWWrite (asynchCommandObjectID);
  1593.     }
  1594.  
  1595.     // Set camera to 320 x 240 4:2:2 YUV.
  1596.     if (result == noErr)
  1597.     {
  1598.         fwCCMReg = 0x20000000;
  1599.         asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  1600.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  1601.                                         0x0000FFFF,
  1602.                                         pFWCCMDriverData->regBaseAddress + 0x0604,
  1603.                                         (Ptr) &fwCCMReg,
  1604.                                         4);
  1605.  
  1606.         FWCCMDelayForHardware (100*durationMillisecond);
  1607.         result = FWWrite (asynchCommandObjectID);
  1608.     }
  1609.  
  1610.     // Initialize VDig data.
  1611.     //zzz defs???
  1612.     if (result == noErr)
  1613.     {
  1614.         pFWCCMVDigData->pFWCCMDriverData = pFWCCMDriverData;
  1615.         pFWCCMVDigData->digitizerRect.top = 0;
  1616.         pFWCCMVDigData->digitizerRect.left = 0;
  1617.         pFWCCMVDigData->digitizerRect.bottom = 240;
  1618.         pFWCCMVDigData->digitizerRect.right = 320;
  1619.     }
  1620.  
  1621.     // Set component storage.
  1622.     if (result == noErr)
  1623.     {
  1624.         SetComponentInstanceStorage (pComponentOpenParams->componentInstance,
  1625.                                      fwCCMVDigDataHandle);
  1626.     }
  1627.  
  1628. /*zzz*/
  1629. #if 0
  1630.     // Clean up on error.
  1631.     if (result != noErr)
  1632.     {
  1633.  
  1634.         //zzz Note, the large memory allocs are cleaned up above if we fail
  1635.         // due to running out of memory (but not for any other reason).
  1636.  
  1637.         if (fwCCMVDigDataHandle != nil)
  1638.             DisposeHandle (fwCCMVDigDataHandle);
  1639.     }
  1640. #endif
  1641. /*zzz*/
  1642.  
  1643.     return result;
  1644. }
  1645.  
  1646.  
  1647. ////////////////////////////////////////////////////////////////////////////////
  1648. //
  1649. // FWCCMWriteDCLProgram
  1650. //
  1651. //   This routine is called once, each time we are opened.  It constructs a DCL
  1652. //   program suitable for all three kinds of receive (playthrough, sync grab,
  1653. //   and async grab).  As the usage changes, only the callProc will be varied (but
  1654. //   not while the DCL program actually runs).
  1655. //
  1656. //   The DCL program consists of consecutive frame-sized sets of receive buffers.
  1657. //   If we can't keep up with the received data, whole frames will be skipped.
  1658. //   But, we never skip a frame and then immediately want one that isn't there,
  1659. //   because we have a total of three frames.
  1660. //
  1661. //   The high level structure looks like this:
  1662. //      Receive frame 1, branch to frame 2.
  1663. //      Receive frame 2, branch to frame 3.
  1664. //      Receive frame 3, branch to frame 3.
  1665. //
  1666. //      ** Note:  Frame 3 will be overwritten with frames 4, 5, 6, etc., unless we
  1667. //                change the branch that follows it, before that branch is reached.
  1668. //                Our goal is to do so, unless the CPU can't keep up.
  1669. // 
  1670. //   Once frame 1 has been received and processed, and the buffer is again
  1671. //   available, the DMA is running somewhere in frame 2 or 3.  The branches
  1672. //   are then changed so that the high-level structure now looks like this:
  1673. //      Receive frame 1, branch to frame 1.
  1674. //      Receive frame 2, branch to frame 3.
  1675. //      Receive frame 3, branch to frame 1.
  1676. //
  1677. //   If we had only two frame buffers, and the CPU speed varied (due to other loads)
  1678. //   and we had to sometimes skip frames, we might have the following sequence of
  1679. //   events:  We are processing frame 1.  Frame 2 completes, and the DMA starts to
  1680. //   receive frame 3 into the same buffer.  But now we get full use of the CPU for
  1681. //   a while.  We wrap up frame 1, and charge into frame 3 - and we overtake the DMA,
  1682. //   which is still filling in frame 3.  So we glitch the video, because we'll show an
  1683. //   image that is partly frame 3 and partly frame 2.  The three-buffer solution used
  1684. //   here prevents this problem.
  1685. //
  1686. //   The lower level structure of the DCL program for a single frame looks like this:
  1687. //      kDCLLabelOp "preFrame"
  1688. //      kDCLReceivePacketStartOp x 240
  1689. //      kDCLJumpOp
  1690. //      kDCLLabelOp "postFrame"
  1691. //      kDCLUpdateDCLListOp
  1692. //      kDCLCallProcOp
  1693. //
  1694. //   Usually, the Jump points to the "postFrame" label that follows it, meaning the
  1695. //   jump has no real effect.  But in the "overflow" frame at the end of the DCL program,
  1696. //   the Jump points to the "preFrame" label that heads the frame, making the DMA fill
  1697. //   the same buffer again.  Because the Jump takes place before the update and the
  1698. //   callProc, these tasks can be avoided when a frame of data is overwritten, to
  1699. //   save time (and maybe help catch up).
  1700. //
  1701. //   Note that while the high-level description shows a branch to the next frame, the
  1702. //   actual Jump normally just moves execution forward by one DCL.  After each callProc,
  1703. //   the DCLs for the next frame will begin.  [Except at the end of program memory,
  1704. //   where there is an extra Jump back to the top of the DCL program.]
  1705. //
  1706. //   The use of large, frame-sized blocks of DCLs serves three purposes.  First, it allows
  1707. //   for the preservation of vertical lock in systems such as Pele that cannot detect
  1708. //   the start-of-frame sync pattern in an already-running DMA program.  Second, even for
  1709. //   systems that could detect sync (OpenHCI, Lynx), this DMA arrangement neatly skips
  1710. //   whole frames of data, without forcing the CPU to spend extra time taking callProcs
  1711. //   for data that will not be used.  Finally, the use of three frames means that we can
  1712. //   degrade gracefully when we cannot keep up.  For example, with a two-frame (or smaller)
  1713. //   program, if we can't keep up with 30 fps, we'll end up dropping every other frame
  1714. //   and netting about 15 fps.  The three-frame program, however, can degrade to 29, 28,
  1715. //   or some other fps, because it has more elasticity.
  1716.  
  1717. static void FWCCMWriteDCLProgram(
  1718.     FWCCMVDigDataPtr            pFWCCMVDigData)
  1719. {
  1720.     Ptr                            pDCLCommand;
  1721.     DCLLabelPtr                    pStartDCLLabel,
  1722.                                 pPreFrameDCLLabel,
  1723.                                 pPostFrameDCLLabel;
  1724.     DCLTransferPacketPtr        pDCLTransferPacket,
  1725.                                 pFirstDCLTransferPacket;
  1726.     DCLCallProcPtr                pDCLCallProc;
  1727.     DCLJumpPtr                    pDCLJump;
  1728.     DCLUpdateDCLListPtr            pDCLUpdateDCLList;
  1729.     DCLCommandPtr                *updateDCLList,
  1730.                                 *frameUpdateDCLList;
  1731.     UInt32                        updateListSize;
  1732.     Ptr                            frameBuffer;
  1733.     UInt32                        frameNum,
  1734.                                 packetNum;
  1735.  
  1736.     DebugStrStatus ((ConstStr255Param) "\pFWCCMWriteDCLProgram");
  1737.  
  1738.     pDCLCommand = (Ptr) pFWCCMVDigData->dclList;
  1739.  
  1740.     // We build several update lists by carving up this block of memory:
  1741.     updateDCLList = pFWCCMVDigData->updateDCLList;
  1742.  
  1743.     // Create label for start of program.
  1744.     pStartDCLLabel = (DCLLabelPtr) pDCLCommand;
  1745.     pDCLCommand += sizeof (DCLLabel);
  1746.     pStartDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
  1747.     pStartDCLLabel->opcode = kDCLLabelOp;
  1748.  
  1749.     // Create kNumFrameBufs (3) buffer lists of kNumPacketsPerFrameBuf (240)
  1750.     // packets each.
  1751.     for (frameNum = 0; frameNum < kNumFrameBufs; frameNum++)
  1752.     {
  1753.         frameBuffer = pFWCCMVDigData->frameBuf[frameNum];
  1754.  
  1755.         // Create label for start of frame.
  1756.         pPreFrameDCLLabel = (DCLLabelPtr) pDCLCommand;
  1757.         pDCLCommand += sizeof (DCLLabel);
  1758.         pPreFrameDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
  1759.         pPreFrameDCLLabel->opcode = kDCLLabelOp;
  1760.  
  1761.         // Create transfer PCL for each packet.
  1762.         pFirstDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  1763.         frameUpdateDCLList = updateDCLList;
  1764.         updateListSize = 0;
  1765.         for (packetNum = 0; packetNum < kNumPacketsPerFrameBuf; packetNum++)
  1766.         {
  1767.             // Receive one packet up to kReceiveCCMMaxPacketSize bytes.
  1768.             pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  1769.             pDCLCommand += sizeof (DCLTransferPacket);
  1770.             pDCLTransferPacket->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
  1771.             pDCLTransferPacket->opcode = kDCLReceivePacketStartOp;
  1772.             pDCLTransferPacket->buffer = frameBuffer;
  1773.             pDCLTransferPacket->size = kReceiveCCMMaxPacketSize;
  1774.             *updateDCLList++ = (DCLCommandPtr) pDCLTransferPacket;
  1775.             updateListSize++;
  1776.             frameBuffer += kReceiveCCMMaxPacketSize;
  1777.         }
  1778.  
  1779.         // Create jump DCL.
  1780.         //   Normally just jump forward one DCL.
  1781.         //   But, repeat the last buffer if we are running behind.
  1782.         pDCLJump = (DCLJumpPtr) pDCLCommand;
  1783.         pDCLCommand += sizeof (DCLJump);
  1784.         pDCLJump->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
  1785.         pDCLJump->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag;
  1786.         pDCLJump->pJumpDCLLabel = (DCLLabelPtr) pDCLCommand;        // modify later
  1787.  
  1788.         // Create label for end of frame.
  1789.         pPostFrameDCLLabel = (DCLLabelPtr) pDCLCommand;
  1790.         pDCLCommand += sizeof (DCLLabel);
  1791.         pPostFrameDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
  1792.         pPostFrameDCLLabel->opcode = kDCLLabelOp;
  1793.  
  1794.         // Create update DCL list.
  1795.         pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
  1796.         pDCLCommand += sizeof (DCLUpdateDCLList);
  1797.         pDCLUpdateDCLList->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
  1798.         pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp;
  1799.         pDCLUpdateDCLList->dclCommandList = frameUpdateDCLList;
  1800.         pDCLUpdateDCLList->numDCLCommands = updateListSize;
  1801.  
  1802.         // Call a function to consume the received data.
  1803.         pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
  1804.         pDCLCommand += sizeof (DCLCallProc);
  1805.         pDCLCallProc->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
  1806.         pDCLCallProc->opcode = kDCLCallProcOp;
  1807.         pDCLCallProc->proc = 0;                                        // fill in later
  1808.         pDCLCallProc->procData = (UInt32) pFWCCMVDigData;            // all use this data
  1809.  
  1810.         // Record some information about this frame that we'll use later.
  1811.         pFWCCMVDigData->preFrameDCLLabel[frameNum] = pPreFrameDCLLabel;
  1812.         pFWCCMVDigData->firstDCLTransferPacket[frameNum] = pFirstDCLTransferPacket;
  1813.         pFWCCMVDigData->postFrameDCLJump[frameNum] = pDCLJump;
  1814.         pFWCCMVDigData->postFrameDCLLabel[frameNum] = pPostFrameDCLLabel;
  1815.         pFWCCMVDigData->postFrameDCLCallProc[frameNum] = pDCLCallProc;
  1816.     }
  1817.  
  1818.     // Create jump DCL to loop to the top of the program.
  1819.     pDCLJump = (DCLJumpPtr) pDCLCommand;
  1820.     pDCLCommand += sizeof (DCLJump);                                // unused
  1821.     pDCLJump->pNextDCLCommand = (DCLCommandPtr) nil;                // end of program memory
  1822.     pDCLJump->opcode = kDCLJumpOp;
  1823.     pDCLJump->pJumpDCLLabel = pStartDCLLabel;
  1824.  
  1825.     // The DCL program is now ready to use, except that the callProcs have
  1826.     // not been filled in, and the jumps all point forward.  (In normal use
  1827.     // one of the jumps will loop to the frame that was just completed.)
  1828. }
  1829.  
  1830.  
  1831. ////////////////////////////////////////////////////////////////////////////////
  1832. //
  1833. // FWCCMSetupDCLProgram
  1834. //
  1835. //   This routine is called once each time we are going to start up the DCL
  1836. //   program.  This routine sets the callProcs depending on the usage of
  1837. //   the program, and it resets all of the jumps within the program.
  1838. //
  1839. //   See extensive comments in FWCCMWriteDCLProgram for more information.
  1840. //
  1841.  
  1842. static void FWCCMSetupDCLProgram(
  1843.     FWCCMVDigDataPtr            pFWCCMVDigData,
  1844.     DCLCallCommandProcPtr        callProc)
  1845. {
  1846.     DCLLabelPtr                    pPreFrameDCLLabel,
  1847.                                 pPostFrameDCLLabel;
  1848.     DCLCallProcPtr                pDCLCallProc;
  1849.     DCLJumpPtr                    pDCLJump;
  1850.     UInt32                        frameNum;
  1851.  
  1852.     for (frameNum = 0; frameNum < kNumFrameBufs; frameNum++)
  1853.     {
  1854.         // Get DCL pointers we saved earlier:
  1855.         pPreFrameDCLLabel = pFWCCMVDigData->preFrameDCLLabel[frameNum];
  1856.         pDCLJump = pFWCCMVDigData->postFrameDCLJump[frameNum];
  1857.         pPostFrameDCLLabel = pFWCCMVDigData->postFrameDCLLabel[frameNum];
  1858.         pDCLCallProc = pFWCCMVDigData->postFrameDCLCallProc[frameNum];
  1859.  
  1860.         // Set the CallProc as given
  1861.         pDCLCallProc->proc = callProc;
  1862.  
  1863.         // Set the Jump forward
  1864.         pDCLJump->pJumpDCLLabel = pPostFrameDCLLabel;
  1865.     }
  1866.  
  1867.     // Change the last jump to loop on itself
  1868.     pDCLJump->pJumpDCLLabel = pPreFrameDCLLabel;
  1869.  
  1870.     // Do the first frame first
  1871.     pFWCCMVDigData->pendingFrameNum = 0;
  1872.     pFWCCMVDigData->pendingFrameCount = 0;
  1873.     pFWCCMVDigData->pendingFrameFragments = 0;
  1874.  
  1875.     // The DCL program is now ready to run.
  1876. }
  1877.  
  1878.  
  1879. ////////////////////////////////////////////////////////////////////////////////
  1880. //
  1881. // FWCCMSetDCLProgramEndFrame
  1882. //
  1883. //   This routine rewrites the jumps in the running DCL program to place the
  1884. //   specified frame buffer at the end of the program, and make it loop to itself.
  1885. //   The previous self-looping end frame is also fixed up.
  1886. //
  1887. //   See extensive comments in FWCCMWriteDCLProgram for more information.
  1888. //
  1889.  
  1890. static void FWCCMSetDCLProgramEndFrame(
  1891.     FWCCMVDigDataPtr            pFWCCMVDigData,
  1892.     UInt32                        endFrameNum)
  1893. {
  1894.     DCLProgramID                dclProgramID;
  1895.     UInt32                        prevFrameNum;
  1896.     DCLLabelPtr                    pPreFrameDCLLabel,
  1897.                                 pPostFrameDCLLabel;
  1898.     DCLJumpPtr                    pDCLJump;
  1899.  
  1900.     dclProgramID = pFWCCMVDigData->dclProgramID;
  1901.     prevFrameNum = (endFrameNum + (kNumFrameBufs - 1)) % kNumFrameBufs;
  1902.  
  1903.     // First make the new end frame loop to itself.
  1904.     pPreFrameDCLLabel = pFWCCMVDigData->preFrameDCLLabel[endFrameNum];
  1905.     pDCLJump = pFWCCMVDigData->postFrameDCLJump[endFrameNum];
  1906.  
  1907.     FWModifyDCLJump (dclProgramID, pDCLJump, pPreFrameDCLLabel);
  1908.  
  1909.     // Now make the previous end frame no longer loop to itself.
  1910.     pPostFrameDCLLabel = pFWCCMVDigData->postFrameDCLLabel[prevFrameNum];
  1911.     pDCLJump = pFWCCMVDigData->postFrameDCLJump[prevFrameNum];
  1912.  
  1913.     FWModifyDCLJump (dclProgramID, pDCLJump, pPostFrameDCLLabel);
  1914. }
  1915.  
  1916.  
  1917. ////////////////////////////////////////////////////////////////////////////////
  1918. //
  1919. // FWCCMClose
  1920. //
  1921. //   Close routine for FireWire CCM VDig component.
  1922. //
  1923.  
  1924. static pascal ComponentResult    FWCCMClose(
  1925.     Handle                        componentSpecificData,
  1926.     ComponentCloseParamsPtr        pComponentCloseParams)
  1927. {
  1928.     FWCommandObjectID            isochChannelCommandObjectID;
  1929.     FWCCMVDigDataPtr            pFWCCMVDigData;
  1930.     FWCCMDriverDataPtr            pFWCCMDriverData;
  1931.     UInt32                        i;
  1932.  
  1933. /*zzz*/
  1934.     DebugStrStatus ((ConstStr255Param) "\pClose component");
  1935. /*zzz*/
  1936.     // Deallocate our data.
  1937.     if (componentSpecificData != nil)
  1938.     {
  1939.         // Get our VDig data.
  1940.         pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  1941.         pFWCCMDriverData = pFWCCMVDigData->pFWCCMDriverData;
  1942.  
  1943.         // Release isochronous channel.
  1944.         if (pFWCCMVDigData->channelInitialized)
  1945.         {
  1946.             isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  1947.             FWSetFWCommandParams (isochChannelCommandObjectID,
  1948.                                   kInvalidFWReferenceID,
  1949.                                   kFWCommandSyncFlag,
  1950.                                   nil,
  1951.                                   0);
  1952.             FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  1953.                                                     pFWCCMVDigData->isochChannelID);
  1954.  
  1955.             pFWCCMVDigData->channelActive = false;
  1956.             FWStopIsochronousChannel (isochChannelCommandObjectID);
  1957.  
  1958.             isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  1959.             FWSetFWCommandParams (isochChannelCommandObjectID,
  1960.                                   kInvalidFWReferenceID,
  1961.                                   kFWCommandSyncFlag,
  1962.                                   nil,
  1963.                                   0);
  1964.             FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  1965.                                                     pFWCCMVDigData->isochChannelID);
  1966.  
  1967.             FWReleaseIsochronousChannel (isochChannelCommandObjectID);
  1968.         }
  1969.  
  1970.         // Deallocate FireWire command object for sending isoch port commands.
  1971.         if (pFWCCMVDigData->isochPortCommandObjectID != kInvalidFWCommandObjectID)
  1972.             FWDeallocateFWCommandObject (pFWCCMVDigData->isochPortCommandObjectID);
  1973.  
  1974.         // Deallocate FireWire command object for sending asynchronous stop
  1975.         // isoch channel commands.
  1976.         if (pFWCCMVDigData->stopIsochChannelCommandObjectID != kInvalidFWCommandObjectID)
  1977.             FWDeallocateFWCommandObject (pFWCCMVDigData->stopIsochChannelCommandObjectID);
  1978.     
  1979.         // Deallocate FireWire command object for sending asynchronous start
  1980.         // isoch channel commands.
  1981.         if (pFWCCMVDigData->startIsochChannelCommandObjectID != kInvalidFWCommandObjectID)
  1982.             FWDeallocateFWCommandObject (pFWCCMVDigData->startIsochChannelCommandObjectID);
  1983.     
  1984.         // Deallocate FireWire command object for sending isoch channel commands.
  1985.         if (pFWCCMVDigData->isochChannelCommandObjectID != kInvalidFWCommandObjectID)
  1986.             FWDeallocateFWCommandObject (pFWCCMVDigData->isochChannelCommandObjectID);
  1987.     
  1988.         // Deallocate FireWire command object for sending asynchronous packets.
  1989.         if (pFWCCMVDigData->asynchCommandObjectID != kInvalidFWCommandObjectID)
  1990.             FWDeallocateFWCommandObject (pFWCCMVDigData->asynchCommandObjectID);
  1991.     
  1992.         // Deallocate FireWire command object for sending camera start asynchronous
  1993.         // packets.
  1994.         if (pFWCCMVDigData->startAsynchCommandObjectID != kInvalidFWCommandObjectID)
  1995.             FWDeallocateFWCommandObject (pFWCCMVDigData->startAsynchCommandObjectID);
  1996.     
  1997.         // Deallocate FireWire command object for sending camera stop asynchronous
  1998.         // packets.
  1999.         if (pFWCCMVDigData->stopAsynchCommandObjectID != kInvalidFWCommandObjectID)
  2000.             FWDeallocateFWCommandObject (pFWCCMVDigData->stopAsynchCommandObjectID);
  2001.     
  2002.         // Deallocate isochronous channel ID for receiving video data.
  2003.         if (pFWCCMVDigData->isochChannelID != kInvalidIsochChannelID)
  2004.             FWDeallocateIsochronousChannelID (pFWCCMVDigData->isochChannelID);
  2005.     
  2006.         // Deallocate YUV to RGB tables.
  2007.         if (pFWCCMVDigData->yuvToRGB32Table)
  2008.             PoolDeallocate ((Ptr) pFWCCMVDigData->yuvToRGB32Table);
  2009.  
  2010.         if (pFWCCMVDigData->yuvToRGB16Table)
  2011.             PoolDeallocate ((Ptr) pFWCCMVDigData->yuvToRGB16Table);
  2012.  
  2013.         // Deallocate frame buffers.
  2014.         for (i = 0; i < kNumFrameBufs; i++)
  2015.             if (pFWCCMVDigData->frameBuf[i])
  2016.                 PoolDeallocate ((Ptr) pFWCCMVDigData->frameBuf[i]);
  2017.  
  2018.         // Dispose of DCL program.
  2019.         if (pFWCCMVDigData->dclProgramID != kInvalidDCLProgramID)
  2020.             FWDisposeDCLProgram (pFWCCMVDigData->dclProgramID);
  2021.  
  2022.         // Deallocate DCL update list
  2023.         if (pFWCCMVDigData->updateDCLList)
  2024.             PoolDeallocate ((Ptr) pFWCCMVDigData->updateDCLList);
  2025.  
  2026.         // Deallocate DCL list.
  2027.         if (pFWCCMVDigData->dclList)
  2028.             PoolDeallocate ((Ptr) pFWCCMVDigData->dclList);
  2029.  
  2030.         // Deallocate async queue.
  2031.         if (pFWCCMVDigData->vdigBufferRecQueue)
  2032.             PBQueueDelete (pFWCCMVDigData->vdigBufferRecQueue);
  2033.  
  2034.         if (pFWCCMDriverData)
  2035.             pFWCCMDriverData->pFWCCMVDigData = nil;
  2036.         DisposeHandle (componentSpecificData);
  2037.     }
  2038.  
  2039.     return noErr;
  2040. }
  2041.  
  2042.  
  2043. ////////////////////////////////////////////////////////////////////////////////
  2044. //
  2045. // FWCCMVersion
  2046. //
  2047. //   This routine returns the component version.
  2048. //
  2049.  
  2050. static pascal long    FWCCMVersion(
  2051.     Handle                        componentSpecificData)
  2052. {
  2053.     return (vdigInterfaceRev << 16) | 0;    //zzz define code rev
  2054. }
  2055.  
  2056.  
  2057. ////////////////////////////////////////////////////////////////////////////////
  2058. //
  2059. // FWCCMInitializeDriver
  2060. //
  2061. //   This routine does some driver initialization.  It will register with the
  2062. // FireWire family.
  2063. //zzz need to be able to unregister driver on error.
  2064. //
  2065.  
  2066. static pascal ComponentResult    FWCCMInitializeDriver(
  2067.     RegEntryIDPtr                pRegEntryID)
  2068. {
  2069.     FWDriverID                    fwDriverID;
  2070.     ComponentResult                result = noErr;
  2071.  
  2072.     // Allocate driver data record.
  2073.     gpFWCCMDriverData =
  2074.         (FWCCMDriverDataPtr) PoolAllocateResident (sizeof (FWCCMDriverData), true);
  2075.     if (gpFWCCMDriverData == nil)
  2076.         result = memFullErr;
  2077.  
  2078.     // Register with the FireWire family.
  2079.     if (result == noErr)
  2080.     {
  2081.         result = FWRegisterDriver (pRegEntryID,
  2082.                                    &fwDriverID,
  2083.                                    &(gpFWCCMDriverData->csrUnitID),
  2084.                                    (UInt32) gpFWCCMDriverData);
  2085.         if (result == noErr)
  2086.             gpFWCCMDriverData->fwDriverID = fwDriverID;
  2087.     }
  2088.  
  2089.     // Set reset bus management notify interface proc.
  2090.     if (result == noErr)
  2091.     {
  2092.         result = FWSetFWClientBusManagementNotifyProc
  2093.                     ((FWReferenceID) fwDriverID, FWCCMBusManagementNotify);
  2094.     }
  2095.  
  2096.     // Set initialize isoch port interface proc.
  2097.     if (result == noErr)
  2098.     {
  2099.         result = FWSetFWClientInitIsochPortProc
  2100.                     ((FWReferenceID) fwDriverID, FWCCMInitIsochPort);
  2101.     }
  2102.  
  2103.     // Set release isoch port interface proc.
  2104.     if (result == noErr)
  2105.     {
  2106.         result = FWSetFWClientReleaseIsochPortProc
  2107.                     ((FWReferenceID) fwDriverID, FWCCMReleaseIsochPort);
  2108.     }
  2109.  
  2110.     // Set start isoch port interface proc.
  2111.     if (result == noErr)
  2112.     {
  2113.         result = FWSetFWClientStartIsochPortProc
  2114.                     ((FWReferenceID) fwDriverID, FWCCMStartIsochPort);
  2115.     }
  2116.  
  2117.     // Set stop isoch port interface proc.
  2118.     if (result == noErr)
  2119.     {
  2120.         result = FWSetFWClientStopIsochPortProc
  2121.                     ((FWReferenceID) fwDriverID, FWCCMStopIsochPort);
  2122.     }
  2123.  
  2124.     // Clean up on error.
  2125.     if ((result != noErr) && (gpFWCCMDriverData != nil))
  2126.         FWCCMFinalizeDriver (pRegEntryID);
  2127.  
  2128.     return result;
  2129. }
  2130.  
  2131.  
  2132. ////////////////////////////////////////////////////////////////////////////////
  2133. //
  2134. // FWCCMFinalizeDriver
  2135. //
  2136. //   This routine does some driver finalization.  It will unregister with the
  2137. // FireWire family.
  2138. //
  2139.  
  2140. static pascal ComponentResult    FWCCMFinalizeDriver(
  2141.     RegEntryIDPtr                pRegEntryID)
  2142. {
  2143.     ComponentResult                result = noErr;
  2144.  
  2145.     if (gpFWCCMDriverData != nil)
  2146.     {
  2147.         // Unregister with the FireWire family.
  2148.         if (gpFWCCMDriverData->fwDriverID != kInvalidFWDriverID)
  2149.             FWUnregisterDriver (gpFWCCMDriverData->fwDriverID);
  2150.  
  2151.         // Deallocate driver data record.
  2152.         PoolDeallocate ((Ptr) gpFWCCMDriverData);
  2153.         gpFWCCMDriverData = nil;
  2154.     }
  2155.  
  2156.     return result;
  2157. }
  2158.  
  2159.  
  2160. ////////////////////////////////////////////////////////////////////////////////
  2161. //
  2162. // FWCCMGetActiveSrcRect
  2163. //
  2164. //   This routine returns the size and location of the active source
  2165. // rectangle.
  2166. //
  2167.  
  2168. static pascal VideoDigitizerError    FWCCMGetActiveSrcRect(
  2169.     Handle                        componentSpecificData,
  2170.     VDigGetActiveSrcRectParamsPtr
  2171.                                 pVDigGetActiveSrcRectParams)
  2172. {
  2173.     Rect                        *pActiveSrcRect;
  2174.     VideoDigitizerError            vdigErr = noErr;
  2175.  
  2176.     // Validate inputNum.
  2177.     if (pVDigGetActiveSrcRectParams->inputNum > 0)
  2178.     {
  2179.         vdigErr = -1;//zzz is there something better???
  2180.     }
  2181.  
  2182.     // Return active source rect.
  2183.     //zzz should get this out of some data structure.
  2184.     if (vdigErr == noErr)
  2185.     {
  2186.         pActiveSrcRect = pVDigGetActiveSrcRectParams->pActiveSrcRect;
  2187.         pActiveSrcRect->top = 0;
  2188.         pActiveSrcRect->left = 0;
  2189.         pActiveSrcRect->bottom = 240;
  2190.         pActiveSrcRect->right = 320;
  2191.     }
  2192.  
  2193.     return vdigErr;
  2194. }
  2195.  
  2196.  
  2197. ////////////////////////////////////////////////////////////////////////////////
  2198. //
  2199. // FWCCMSetDigitizerRect
  2200. //
  2201. //   This routine sets the current digitizer rectangle.
  2202. //zzz validate rect.
  2203. //
  2204.  
  2205. static pascal VideoDigitizerError    FWCCMSetDigitizerRect(
  2206.     Handle                        componentSpecificData,
  2207.     VDigSetDigitizerRectParamsPtr
  2208.                                 pVDigSetDigitizerRectParams)
  2209. {
  2210.     FWCCMVDigDataPtr            pFWCCMVDigData;
  2211.     VideoDigitizerError            vdigErr = noErr;
  2212.  
  2213.     // Get VDig data.
  2214.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  2215.  
  2216.     // Set digitizer rect.
  2217.     pFWCCMVDigData->digitizerRect = *(pVDigSetDigitizerRectParams->pDigitizerRect);
  2218.  
  2219.     return vdigErr;
  2220. }
  2221.  
  2222.  
  2223. ////////////////////////////////////////////////////////////////////////////////
  2224. //
  2225. // FWCCMGetDigitizerInfo
  2226. //
  2227. //   This routine returns information about the VDig.
  2228. //
  2229.  
  2230. static pascal VideoDigitizerError    FWCCMGetDigitizerInfo(
  2231.     Handle                        componentSpecificData,
  2232.     VDigGetDigitizerInfoParamsPtr
  2233.                                 pVDigGetDigitizerInfoParams)
  2234. {
  2235.     DigitizerInfo                *pDigitizerInfo;
  2236.     VideoDigitizerError            vdigErr = noErr;
  2237.  
  2238.     // Fill out info record.
  2239.     //zzz need to set some things for real
  2240.     pDigitizerInfo = pVDigGetDigitizerInfoParams->pDigitizerInfo;
  2241.     pDigitizerInfo->vdigType = vdTypeBasic;
  2242.     pDigitizerInfo->inputCapabilityFlags = digiInDoesNTSC | /*zzz just fake it*/
  2243.                                            digiInDoesComponent |
  2244.                                            digiInDoesBW |
  2245.                                            digiInDoesColor;
  2246.     pDigitizerInfo->outputCapabilityFlags = digiOutDoes16 |
  2247.                                             digiOutDoes32 |
  2248.                                             digiOutDoesAsyncGrabs |
  2249.                                             digiOutDoesHWPlayThru |
  2250.                                             digiOutDoesHW_DMA;
  2251.     pDigitizerInfo->inputCurrentFlags = digiInDoesNTSC | /*zzz just fake it */
  2252.                                         digiInDoesComponent |
  2253.                                         digiInDoesColor;
  2254.     pDigitizerInfo->outputCurrentFlags = digiOutDoes16 |
  2255.                                          digiOutDoes32 |
  2256.                                          digiOutDoesAsyncGrabs |
  2257.                                          digiOutDoesHWPlayThru |
  2258.                                          digiOutDoesHW_DMA;
  2259.     pDigitizerInfo->slot = 0; /*zzz doesn't really have a slot. */
  2260.     pDigitizerInfo->gdh = nil;
  2261.     pDigitizerInfo->maskgdh = nil;
  2262.     pDigitizerInfo->minDestHeight = 240;
  2263.     pDigitizerInfo->minDestWidth = 320;
  2264.     pDigitizerInfo->maxDestHeight = 480;
  2265.     pDigitizerInfo->maxDestWidth = 640;
  2266.     pDigitizerInfo->blendLevels = 0;
  2267.     pDigitizerInfo->reserved = 0;
  2268.  
  2269.     return vdigErr;
  2270. }
  2271.  
  2272.  
  2273. ////////////////////////////////////////////////////////////////////////////////
  2274. //
  2275. // FWCCMGetCurrentFlags
  2276. //
  2277. //   This routine returns the current state of the VDig.
  2278. //
  2279.  
  2280. static pascal VideoDigitizerError    FWCCMGetCurrentFlags(
  2281.     Handle                        componentSpecificData,
  2282.     VDigGetCurrentFlagsParamsPtr
  2283.                                 pVDigGetCurrentFlagsParams)
  2284. {
  2285.     VideoDigitizerError            vdigErr = noErr;
  2286.  
  2287.     //zzz do these for real
  2288.     *(pVDigGetCurrentFlagsParams->pInputCurrentFlags) =
  2289.         digiInDoesNTSC | /*zzz just fake it */
  2290.         digiInDoesComponent |
  2291.         digiInDoesColor;
  2292.  
  2293.     *(pVDigGetCurrentFlagsParams->pOutputCurrentFlags) =
  2294.         digiOutDoes16 |
  2295.         digiOutDoes32 |
  2296.         digiOutDoesAsyncGrabs |
  2297.         digiOutDoesHWPlayThru |
  2298.         digiOutDoesHW_DMA;
  2299.  
  2300.     return vdigErr;
  2301. }
  2302.  
  2303.  
  2304. ////////////////////////////////////////////////////////////////////////////////
  2305. //
  2306. // FWCCMSetPlayThruDestination
  2307. //
  2308. //   This function establishes the destination settings for the VDig.
  2309. //zzz Should do some parameter checking.
  2310. //zzz Should we CopyPixMap hDestPixMap or just copy the handle???
  2311. //
  2312.  
  2313. static pascal VideoDigitizerError    FWCCMSetPlayThruDestination(
  2314.     Handle                        componentSpecificData,
  2315.     VDigSetPlayThruDestinationParamsPtr
  2316.                                 pVDigSetPlayThruDestinationParams)
  2317. {
  2318.     FWCCMVDigDataPtr            pFWCCMVDigData;
  2319.     VdigBufferRecListHandle        bufferList = nil;
  2320.     VideoDigitizerError            vdigErr = noErr;
  2321.  
  2322. /*zzz*/
  2323.     DebugStrStatus ((ConstStr255Param) "\pFWCCMSetPlayThruDestination");
  2324. /*zzz*/
  2325.     // Get our VDig data.
  2326.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  2327.  
  2328.     // Get pix map and dest rect.
  2329.     pFWCCMVDigData->hDestPixMap = pVDigSetPlayThruDestinationParams->hDestPixMap;
  2330.     pFWCCMVDigData->destRect = *(pVDigSetPlayThruDestinationParams->pDestRect);
  2331.  
  2332.     return vdigErr;
  2333. }
  2334.  
  2335.  
  2336. ////////////////////////////////////////////////////////////////////////////////
  2337. //
  2338. // FWCCMSetPlayThruOnOff
  2339. //
  2340. //   This function controls continuous digitization.
  2341. //
  2342. //   Note: Because all of the work in playthrough is triggered by interrupts from
  2343. //   the isochronous receive DMA, if we are not able to keep up, we may saturate
  2344. //   the CPU and prevent the user from regaining control.
  2345. //
  2346. //   One way to improve this would be to put a callProc at the tail of each frame
  2347. //   before the jump DCL.  This callProc would not touch the data (the Update has
  2348. //   not been reached yet) but will make a note that the DMA made forward progress.
  2349. //   Getting the same such callProc twice in a row tells us we have fallen behind
  2350. //   and a frame was skipped.  If that happens a lot, maybe we should yield the CPU.
  2351. //
  2352.  
  2353. static pascal VideoDigitizerError    FWCCMSetPlayThruOnOff(
  2354.     Handle                        componentSpecificData,
  2355.     VDigSetPlayThruOnOffParamsPtr
  2356.                                 pVDigSetPlayThruOnOffParams)
  2357. {
  2358.     FWCCMVDigDataPtr            pFWCCMVDigData;
  2359.     FWCommandObjectID            isochChannelCommandObjectID;
  2360.     VideoDigitizerError            vdigErr = noErr;
  2361.  
  2362. /*zzz*/
  2363.     if (pVDigSetPlayThruOnOffParams->state)
  2364.         DebugStrStatus ((ConstStr255Param) "\pFWCCMSetPlayThruOnOff on");
  2365.     else
  2366.         DebugStrStatus ((ConstStr255Param) "\pFWCCMSetPlayThruOnOff off");
  2367. /*zzz*/
  2368.     // Get our VDig data.
  2369.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  2370.  
  2371.     // Turn on or off.
  2372.     if (pVDigSetPlayThruOnOffParams->state)
  2373.     {
  2374.         // Release isochronous channel.
  2375.         if (pFWCCMVDigData->channelInitialized)
  2376.         {
  2377.             isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  2378.             FWSetFWCommandParams (isochChannelCommandObjectID,
  2379.                                   kInvalidFWReferenceID,
  2380.                                   kFWCommandSyncFlag,
  2381.                                   nil,
  2382.                                   0);
  2383.             FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2384.                                                     pFWCCMVDigData->isochChannelID);
  2385.  
  2386.             pFWCCMVDigData->channelActive = false;
  2387.             FWStopIsochronousChannel (isochChannelCommandObjectID);
  2388.  
  2389.             isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  2390.             FWSetFWCommandParams (isochChannelCommandObjectID,
  2391.                                   kInvalidFWReferenceID,
  2392.                                   kFWCommandSyncFlag,
  2393.                                   nil,
  2394.                                   0);
  2395.             FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2396.                                                     pFWCCMVDigData->isochChannelID);
  2397.  
  2398.             FWReleaseIsochronousChannel (isochChannelCommandObjectID);
  2399.         }
  2400.  
  2401.         // Reset the jumps and set the callprocs, and set start of DCL program:
  2402.         if (vdigErr == noErr)
  2403.         {
  2404.             FWCCMSetupDCLProgram (pFWCCMVDigData,
  2405.                                   (DCLCallCommandProcPtr) FWCCMPlayThruIsochHandler);
  2406.             vdigErr = FWSetDCLProgramStart (pFWCCMVDigData->dclProgramID,
  2407.                                             pFWCCMVDigData->dclList);
  2408.         }
  2409.     
  2410.         // Initialize isochronous channel.
  2411.         isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  2412.         FWSetFWCommandParams (isochChannelCommandObjectID,
  2413.                               kInvalidFWReferenceID,
  2414.                               kFWCommandSyncFlag,
  2415.                               nil,
  2416.                               0);
  2417.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2418.                                                 pFWCCMVDigData->isochChannelID);
  2419.  
  2420.         vdigErr = FWInitializeIsochronousChannel (isochChannelCommandObjectID);
  2421.  
  2422.         if (vdigErr == noErr)
  2423.         {
  2424.             pFWCCMVDigData->channelInitialized = true;
  2425.             pFWCCMVDigData->currentLocation.v = 0;
  2426.             pFWCCMVDigData->currentLocation.h = 0;
  2427.         }
  2428.     
  2429.         // Start up isochronous channel.
  2430.         if (vdigErr == noErr)
  2431.         {
  2432.             isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  2433.             FWSetFWCommandParams (isochChannelCommandObjectID,
  2434.                                   kInvalidFWReferenceID,
  2435.                                   kFWCommandSyncFlag,
  2436.                                   nil,
  2437.                                   0);
  2438.             FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2439.                                                     pFWCCMVDigData->isochChannelID);
  2440.     
  2441.             pFWCCMVDigData->channelActive = true;
  2442.             vdigErr = FWStartIsochronousChannel (isochChannelCommandObjectID);
  2443.         }
  2444.     }
  2445.     else
  2446.     {
  2447.         // Release isochronous channel.
  2448.         if (pFWCCMVDigData->channelInitialized)
  2449.         {
  2450.             isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  2451.             FWSetFWCommandParams (isochChannelCommandObjectID,
  2452.                                   kInvalidFWReferenceID,
  2453.                                   kFWCommandSyncFlag,
  2454.                                   nil,
  2455.                                   0);
  2456.             FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2457.                                                     pFWCCMVDigData->isochChannelID);
  2458.     
  2459.             pFWCCMVDigData->channelActive = false;
  2460.             FWStopIsochronousChannel (isochChannelCommandObjectID);
  2461.  
  2462.             isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  2463.             FWSetFWCommandParams (isochChannelCommandObjectID,
  2464.                                   kInvalidFWReferenceID,
  2465.                                   kFWCommandSyncFlag,
  2466.                                   nil,
  2467.                                   0);
  2468.             FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2469.                                                     pFWCCMVDigData->isochChannelID);
  2470.     
  2471.             FWReleaseIsochronousChannel (isochChannelCommandObjectID);
  2472.         }
  2473.         pFWCCMVDigData->channelInitialized = false;
  2474.     }
  2475.  
  2476.     return vdigErr;
  2477. }
  2478.  
  2479.  
  2480. ////////////////////////////////////////////////////////////////////////////////
  2481. //
  2482. // FWCCMSetHue
  2483. //
  2484. //   This function sets the hue for the camera.
  2485. //
  2486.  
  2487. static pascal VideoDigitizerError    FWCCMSetHue(
  2488.     Handle                        componentSpecificData,
  2489.     VDigSetHueParamsPtr            pVDigSetHueParams)
  2490. {
  2491.     FWCCMVDigDataPtr            pFWCCMVDigData;
  2492.     FWCCMDriverDataPtr            pFWCCMDriverData;
  2493.     FWCommandObjectID            asynchCommandObjectID;
  2494.     UInt32                        fwCCMReg;
  2495.     UInt32                        minValue,
  2496.                                 maxValue;
  2497.     unsigned short                *pHue;
  2498.     UInt32                        hue;
  2499.     VideoDigitizerError            vdigErr = noErr;
  2500.  
  2501.     // Get our VDig data.
  2502.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  2503.  
  2504.     // Get our driver data.
  2505.     pFWCCMDriverData = pFWCCMVDigData->pFWCCMDriverData;
  2506.  
  2507.     // Read the min/max value for the hue register.
  2508.     asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  2509.     FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2510.                                     0x0000FFFF,
  2511.                                     pFWCCMDriverData->regBaseAddress + 0x0510,
  2512.                                     (Ptr) &fwCCMReg,
  2513.                                     4);
  2514.  
  2515.     vdigErr = FWRead (asynchCommandObjectID);
  2516.     minValue = (fwCCMReg & 0x00FFF000) >> 12;
  2517.     maxValue = fwCCMReg & 0x0FFF;
  2518.  
  2519.     // Scale hue value.
  2520.     if (vdigErr == noErr)
  2521.     {
  2522.         pHue = pVDigSetHueParams->pHue;
  2523.         hue = minValue + (((*pHue)*(maxValue - minValue)) >> 16);
  2524.     }
  2525.  
  2526.     // Write the hue register in the camera.
  2527.     if (vdigErr == noErr)
  2528.     {
  2529.         fwCCMReg = 0x82000000 | hue;
  2530.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2531.                                         0x0000FFFF,
  2532.                                         pFWCCMDriverData->regBaseAddress + 0x0810,
  2533.                                         (Ptr) &fwCCMReg,
  2534.                                         4);
  2535.  
  2536.         FWCCMDelayForHardware (100*durationMillisecond);
  2537.         vdigErr = FWWrite (asynchCommandObjectID);
  2538.     }
  2539.  
  2540.     return vdigErr;
  2541. }
  2542.  
  2543.  
  2544. ////////////////////////////////////////////////////////////////////////////////
  2545. //
  2546. // FWCCMSetSaturation
  2547. //
  2548. //   This function sets the saturation for the camera.
  2549. //
  2550.  
  2551. static pascal VideoDigitizerError    FWCCMSetSaturation(
  2552.     Handle                        componentSpecificData,
  2553.     VDigSetSaturationParamsPtr    pVDigSetSaturationParams)
  2554. {
  2555.     FWCCMVDigDataPtr            pFWCCMVDigData;
  2556.     FWCCMDriverDataPtr            pFWCCMDriverData;
  2557.     FWCommandObjectID            asynchCommandObjectID;
  2558.     UInt32                        fwCCMReg;
  2559.     UInt32                        minValue,
  2560.                                 maxValue;
  2561.     unsigned short                *pSaturation;
  2562.     UInt32                        saturation;
  2563.     VideoDigitizerError            vdigErr = noErr;
  2564.  
  2565.     // Get our VDig data.
  2566.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  2567.  
  2568.     // Get our driver data.
  2569.     pFWCCMDriverData = pFWCCMVDigData->pFWCCMDriverData;
  2570.  
  2571.     // Read the min/max value for the saturation register.
  2572.     asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  2573.     FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2574.                                     0x0000FFFF,
  2575.                                     pFWCCMDriverData->regBaseAddress + 0x0514,
  2576.                                     (Ptr) &fwCCMReg,
  2577.                                     4);
  2578.  
  2579.     vdigErr = FWRead (asynchCommandObjectID);
  2580.     minValue = (fwCCMReg & 0x00FFF000) >> 12;
  2581.     maxValue = fwCCMReg & 0x0FFF;
  2582.  
  2583.     // Scale saturation value.
  2584.     if (vdigErr == noErr)
  2585.     {
  2586.         pSaturation = pVDigSetSaturationParams->pSaturation;
  2587.         saturation = minValue + (((*pSaturation)*(maxValue - minValue)) >> 16);
  2588.     }
  2589.  
  2590.     // Write the saturation register in the camera.
  2591.     if (vdigErr == noErr)
  2592.     {
  2593.         fwCCMReg = 0x82000000 | saturation;
  2594.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2595.                                         0x0000FFFF,
  2596.                                         pFWCCMDriverData->regBaseAddress + 0x0814,
  2597.                                         (Ptr) &fwCCMReg,
  2598.                                         4);
  2599.  
  2600.         FWCCMDelayForHardware (100*durationMillisecond);
  2601.         vdigErr = FWWrite (asynchCommandObjectID);
  2602.     }
  2603.  
  2604.     return vdigErr;
  2605. }
  2606.  
  2607.  
  2608. ////////////////////////////////////////////////////////////////////////////////
  2609. //
  2610. // FWCCMGetHue
  2611. //
  2612. //   This function gets the hue for the camera.
  2613. //
  2614.  
  2615. static pascal VideoDigitizerError    FWCCMGetHue(
  2616.     Handle                        componentSpecificData,
  2617.     VDigGetHueParamsPtr            pVDigGetHueParams)
  2618. {
  2619.     FWCCMVDigDataPtr            pFWCCMVDigData;
  2620.     FWCCMDriverDataPtr            pFWCCMDriverData;
  2621.     FWCommandObjectID            asynchCommandObjectID;
  2622.     UInt32                        fwCCMReg;
  2623.     UInt32                        minValue,
  2624.                                 maxValue;
  2625.     VideoDigitizerError            vdigErr = noErr;
  2626.  
  2627.     // Get our VDig data.
  2628.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  2629.  
  2630.     // Get our driver data.
  2631.     pFWCCMDriverData = pFWCCMVDigData->pFWCCMDriverData;
  2632.  
  2633.     // Read the min/max value for the hue register.
  2634.     asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  2635.     FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2636.                                     0x0000FFFF,
  2637.                                     pFWCCMDriverData->regBaseAddress + 0x0510,
  2638.                                     (Ptr) &fwCCMReg,
  2639.                                     4);
  2640.  
  2641.     vdigErr = FWRead (asynchCommandObjectID);
  2642.     minValue = (fwCCMReg & 0x00FFF000) >> 12;
  2643.     maxValue = fwCCMReg & 0x0FFF;
  2644.  
  2645.     // Read the hue register in the camera.
  2646.     if (vdigErr == noErr)
  2647.     {
  2648.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2649.                                         0x0000FFFF,
  2650.                                         pFWCCMDriverData->regBaseAddress + 0x0810,
  2651.                                         (Ptr) &fwCCMReg,
  2652.                                         4);
  2653.  
  2654.         vdigErr = FWRead (asynchCommandObjectID);
  2655.     }
  2656.  
  2657.     // Return scaled result.
  2658.     if (vdigErr == noErr)
  2659.     {
  2660.         *(pVDigGetHueParams->pHue) =
  2661.             (((fwCCMReg & 0x0FFF) - minValue) << 16) / (maxValue - minValue);
  2662.     }
  2663.  
  2664.     return vdigErr;
  2665. }
  2666.  
  2667.  
  2668. ////////////////////////////////////////////////////////////////////////////////
  2669. //
  2670. // FWCCMGetSaturation
  2671. //
  2672. //   This function gets the saturation for the camera.
  2673. //
  2674.  
  2675. static pascal VideoDigitizerError    FWCCMGetSaturation(
  2676.     Handle                        componentSpecificData,
  2677.     VDigGetSaturationParamsPtr    pVDigGetSaturationParams)
  2678. {
  2679.     FWCCMVDigDataPtr            pFWCCMVDigData;
  2680.     FWCCMDriverDataPtr            pFWCCMDriverData;
  2681.     FWCommandObjectID            asynchCommandObjectID;
  2682.     UInt32                        fwCCMReg;
  2683.     UInt32                        minValue,
  2684.                                 maxValue;
  2685.     VideoDigitizerError            vdigErr = noErr;
  2686.  
  2687.     // Get our VDig data.
  2688.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  2689.  
  2690.     // Get our driver data.
  2691.     pFWCCMDriverData = pFWCCMVDigData->pFWCCMDriverData;
  2692.  
  2693.     // Read the min/max value for the saturation register.
  2694.     asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  2695.     FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2696.                                     0x0000FFFF,
  2697.                                     pFWCCMDriverData->regBaseAddress + 0x0514,
  2698.                                     (Ptr) &fwCCMReg,
  2699.                                     4);
  2700.  
  2701.     vdigErr = FWRead (asynchCommandObjectID);
  2702.     minValue = (fwCCMReg & 0x00FFF000) >> 12;
  2703.     maxValue = fwCCMReg & 0x0FFF;
  2704.  
  2705.     // Read the saturation register in the camera.
  2706.     if (vdigErr == noErr)
  2707.     {
  2708.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2709.                                         0x0000FFFF,
  2710.                                         pFWCCMDriverData->regBaseAddress + 0x0814,
  2711.                                         (Ptr) &fwCCMReg,
  2712.                                         4);
  2713.  
  2714.         vdigErr = FWRead (asynchCommandObjectID);
  2715.     }
  2716.  
  2717.     // Return scaled result.
  2718.     if (vdigErr == noErr)
  2719.     {
  2720.         *(pVDigGetSaturationParams->pSaturation) =
  2721.             (((fwCCMReg & 0x0FFF) - minValue) << 16) / (maxValue - minValue);
  2722.     }
  2723.  
  2724.     return vdigErr;
  2725. }
  2726.  
  2727.  
  2728. ////////////////////////////////////////////////////////////////////////////////
  2729. //
  2730. // FWCCMGrabOneFrame
  2731. //
  2732. //   This function synchronously grabs one frame of data.
  2733. //   This is used when we are watching video on the screen, but can't do
  2734. //   playthrough (window size is wrong, color depth is wrong, etc.).
  2735. //
  2736.  
  2737. static pascal VideoDigitizerError    FWCCMGrabOneFrame(
  2738.     Handle                        componentSpecificData)
  2739. {
  2740.     FWCCMVDigDataPtr            pFWCCMVDigData;
  2741.     FWCommandObjectID            isochChannelCommandObjectID;
  2742.     AbsoluteTime                currentTime;
  2743.     AbsoluteTime                timeout;
  2744.     Boolean                        timedOut;
  2745.     VideoDigitizerError            vdigErr = noErr;
  2746.  
  2747. //    DebugStrStatus ((ConstStr255Param) "\pFWCCMGrabOneFrame");
  2748.  
  2749.     // Get our VDig data.
  2750.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  2751.  
  2752.     // Release asynch buffers if we're in asynch mode.
  2753.     if (pFWCCMVDigData->asynchMode)
  2754.         FWCCMReleaseAsyncBuffers (componentSpecificData);
  2755.  
  2756.     // Typically we are doing this over and over, and the DCL program is already
  2757.     // running.  So, initialize isochronous port only if it isn't initialized.
  2758.     if (!(pFWCCMVDigData->channelInitialized))
  2759.     {
  2760.         // Set up DCL program.
  2761.         if (vdigErr == noErr)
  2762.         {
  2763.             FWCCMSetupDCLProgram (pFWCCMVDigData,
  2764.                                   (DCLCallCommandProcPtr) FWCCMGrabOneFrameIsochHandler);
  2765.             vdigErr = FWSetDCLProgramStart (pFWCCMVDigData->dclProgramID,
  2766.                                             pFWCCMVDigData->dclList);
  2767.         }
  2768.     
  2769.         // Initialize isochronous channel.
  2770.         isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  2771.         FWSetFWCommandParams (isochChannelCommandObjectID,
  2772.                               kInvalidFWReferenceID,
  2773.                               kFWCommandSyncFlag,
  2774.                               nil,
  2775.                               0);
  2776.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2777.                                                 pFWCCMVDigData->isochChannelID);
  2778.  
  2779.         vdigErr = FWInitializeIsochronousChannel (isochChannelCommandObjectID);
  2780.         if (vdigErr == noErr)
  2781.             pFWCCMVDigData->channelInitialized = true;
  2782.  
  2783.         // Start isochronous channel.
  2784.         if (vdigErr == noErr)
  2785.         {
  2786.             isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  2787.             FWSetFWCommandParams (isochChannelCommandObjectID,
  2788.                                   kInvalidFWReferenceID,
  2789.                                   kFWCommandSyncFlag,
  2790.                                   nil,
  2791.                                   0);
  2792.             FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2793.                                                     pFWCCMVDigData->isochChannelID);
  2794.     
  2795.             pFWCCMVDigData->channelActive = true;
  2796.             vdigErr = FWStartIsochronousChannel (isochChannelCommandObjectID);
  2797.         }
  2798.     }
  2799.  
  2800.     // Wait until next channel buffer is filled and synced.
  2801.     if (vdigErr == noErr)
  2802.     {
  2803.         // Compute timeout.
  2804.         timeout = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (durationSecond));
  2805.         timedOut = false;
  2806.  
  2807.         // Wait for a conversion buffer to fill or timeout.
  2808.         while ((!((volatile UInt32) pFWCCMVDigData->pendingFrameCount)) &&
  2809.                (!timedOut))
  2810.         {
  2811.             currentTime = UpTime ();
  2812.             if (((timeout.lo < currentTime.lo) && (timeout.hi == currentTime.hi)) ||
  2813.                 (timeout.hi < currentTime.hi))
  2814.             {
  2815.                 timedOut = true;
  2816.             }
  2817.         }
  2818.  
  2819.         // Output frame if we didn't timeout.
  2820.         if (!timedOut)
  2821.             FWCCMCopyToDestPixMap (pFWCCMVDigData);
  2822.     }
  2823.  
  2824.     return vdigErr;
  2825. }
  2826.  
  2827.  
  2828. ////////////////////////////////////////////////////////////////////////////////
  2829. //
  2830. // FWCCMPreflightDestination
  2831. //
  2832. //   This function verifies that the VDig can support the set of destination
  2833. // settings intended for use with the FWCCMSetPlayThruDestination
  2834. // function.
  2835. //zzz Must do more checks.
  2836. //
  2837.  
  2838. static pascal VideoDigitizerError    FWCCMPreflightDestination(
  2839.     Handle                        componentSpecificData,
  2840.     VDigPreflightDestinationParamsPtr
  2841.                                 pVDigPreflightDestinationParams)
  2842. {
  2843.     PixMapHandle                hDestPixMap;
  2844.     VideoDigitizerError            vdigErr = noErr;
  2845.  
  2846. /*zzz*/
  2847.     DebugStrStatus ((ConstStr255Param) "\pFWCCMPreflightDestination");
  2848. /*zzz*/
  2849.     // Check bit depth of pix map.
  2850.     hDestPixMap = pVDigPreflightDestinationParams->hDestPixMap;
  2851.     if (((*hDestPixMap)->pixelSize != 16) && ((*hDestPixMap)->pixelSize != 32))
  2852.         vdigErr = badDepthErr;
  2853.  
  2854.     return vdigErr;
  2855. }
  2856.  
  2857.  
  2858. ////////////////////////////////////////////////////////////////////////////////
  2859. //
  2860. // FWCCMSetBlackLevelValue
  2861. //
  2862. //   This function sets the black level value for the camera.
  2863. //zzz actually, it sets the U part of the white balance
  2864. //
  2865.  
  2866. static pascal VideoDigitizerError    FWCCMSetBlackLevelValue(
  2867.     Handle                        componentSpecificData,
  2868.     VDigSetBlackLevelValueParamsPtr
  2869.                                 pVDigSetBlackLevelValueParams)
  2870. {
  2871.     FWCCMVDigDataPtr            pFWCCMVDigData;
  2872.     FWCCMDriverDataPtr            pFWCCMDriverData;
  2873.     VDigGetWhiteLevelValueParams
  2874.                                 vdigGetWhiteLevelValueParams;
  2875.     FWCommandObjectID            asynchCommandObjectID;
  2876.     UInt32                        fwCCMReg;
  2877.     UInt32                        minValue,
  2878.                                 maxValue;
  2879.     unsigned short                *pBlackLevelValue;
  2880.     UInt32                        blackLevelValue;
  2881.     unsigned short                whiteLevelValue;
  2882.     VideoDigitizerError            vdigErr = noErr;
  2883.  
  2884.     // Get our VDig data.
  2885.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  2886.  
  2887.     // Get our driver data.
  2888.     pFWCCMDriverData = pFWCCMVDigData->pFWCCMDriverData;
  2889.  
  2890.     // Get the white level value.
  2891.     vdigGetWhiteLevelValueParams.pWhiteLevelValue = &whiteLevelValue;
  2892.     vdigErr =
  2893.         FWCCMGetWhiteLevelValue (componentSpecificData, &vdigGetWhiteLevelValueParams);
  2894.  
  2895.     // Read the min/max value for the white balance register and scale
  2896.     // black level value.
  2897.     if (vdigErr == noErr)
  2898.     {
  2899.         asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  2900.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2901.                                         0x0000FFFF,
  2902.                                         pFWCCMDriverData->regBaseAddress + 0x050C,
  2903.                                         (Ptr) &fwCCMReg,
  2904.                                         4);
  2905.  
  2906.         vdigErr = FWRead (asynchCommandObjectID);
  2907.         minValue = (fwCCMReg & 0x00FFF000) >> 12;
  2908.         maxValue = fwCCMReg & 0x0FFF;
  2909.     }
  2910.  
  2911.     // Scale black and white level values.
  2912.     if (vdigErr == noErr)
  2913.     {
  2914.         pBlackLevelValue = pVDigSetBlackLevelValueParams->pBlackLevelValue;
  2915.         blackLevelValue =
  2916.             minValue + (((*pBlackLevelValue)*(maxValue - minValue)) >> 16);
  2917.         whiteLevelValue =
  2918.             minValue + (((whiteLevelValue)*(maxValue - minValue)) >> 16);
  2919.     }
  2920.  
  2921.     // Write the white balance register in the camera.
  2922.     if (vdigErr == noErr)
  2923.     {
  2924.         fwCCMReg = 0x82000000 |
  2925.                    (blackLevelValue << 12) |
  2926.                    whiteLevelValue;
  2927.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2928.                                         0x0000FFFF,
  2929.                                         pFWCCMDriverData->regBaseAddress + 0x080C,
  2930.                                         (Ptr) &fwCCMReg,
  2931.                                         4);
  2932.  
  2933.         FWCCMDelayForHardware (100*durationMillisecond);
  2934.         vdigErr = FWWrite (asynchCommandObjectID);
  2935.     }
  2936.  
  2937.     return vdigErr;
  2938. }
  2939.  
  2940.  
  2941. ////////////////////////////////////////////////////////////////////////////////
  2942. //
  2943. // FWCCMGetBlackLevelValue
  2944. //
  2945. //   This function gets the black level for the camera.
  2946. //zzz actually, it gets the U part of the white balance
  2947. //
  2948.  
  2949. static pascal VideoDigitizerError    FWCCMGetBlackLevelValue(
  2950.     Handle                        componentSpecificData,
  2951.     VDigGetBlackLevelValueParamsPtr
  2952.                                 pVdigGetBlackLevelValueParams)
  2953. {
  2954.     FWCCMVDigDataPtr            pFWCCMVDigData;
  2955.     FWCCMDriverDataPtr            pFWCCMDriverData;
  2956.     FWCommandObjectID            asynchCommandObjectID;
  2957.     UInt32                        fwCCMReg;
  2958.     UInt32                        minValue,
  2959.                                 maxValue;
  2960.     VideoDigitizerError            vdigErr = noErr;
  2961.  
  2962.     // Get our VDig data.
  2963.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  2964.  
  2965.     // Get our driver data.
  2966.     pFWCCMDriverData = pFWCCMVDigData->pFWCCMDriverData;
  2967.  
  2968.     // Read the min/max value for the hue register.
  2969.     asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  2970.     FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2971.                                     0x0000FFFF,
  2972.                                     pFWCCMDriverData->regBaseAddress + 0x050C,
  2973.                                     (Ptr) &fwCCMReg,
  2974.                                     4);
  2975.  
  2976.     vdigErr = FWRead (asynchCommandObjectID);
  2977.     minValue = (fwCCMReg & 0x00FFF000) >> 12;
  2978.     maxValue = fwCCMReg & 0x0FFF;
  2979.  
  2980.     // Read the hue register in the camera.
  2981.     if (vdigErr == noErr)
  2982.     {
  2983.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  2984.                                         0x0000FFFF,
  2985.                                         pFWCCMDriverData->regBaseAddress + 0x080C,
  2986.                                         (Ptr) &fwCCMReg,
  2987.                                         4);
  2988.     
  2989.         vdigErr = FWRead (asynchCommandObjectID);
  2990.     }
  2991.  
  2992.     // Return scaled result.
  2993.     if (vdigErr == noErr)
  2994.     {
  2995.         *(pVdigGetBlackLevelValueParams->pBlackLevelValue) =
  2996.             ((((fwCCMReg & 0x00FFF000) >> 12) - minValue) << 16) /
  2997.             (maxValue - minValue);
  2998.     }
  2999.  
  3000.     return vdigErr;
  3001. }
  3002.  
  3003.  
  3004. ////////////////////////////////////////////////////////////////////////////////
  3005. //
  3006. // FWCCMSetWhiteLevelValue
  3007. //
  3008. //   This function sets the white level value for the camera.
  3009. //zzz actually, it sets the V part of the white balance
  3010. //
  3011.  
  3012. static pascal VideoDigitizerError    FWCCMSetWhiteLevelValue(
  3013.     Handle                        componentSpecificData,
  3014.     VDigSetWhiteLevelValueParamsPtr
  3015.                                 pVDigSetWhiteLevelValueParams)
  3016. {
  3017.     FWCCMVDigDataPtr            pFWCCMVDigData;
  3018.     FWCCMDriverDataPtr            pFWCCMDriverData;
  3019.     VDigGetBlackLevelValueParams
  3020.                                 vdigGetBlackLevelValueParams;
  3021.     FWCommandObjectID            asynchCommandObjectID;
  3022.     UInt32                        fwCCMReg;
  3023.     UInt32                        minValue,
  3024.                                 maxValue;
  3025.     unsigned short                *pWhiteLevelValue;
  3026.     UInt32                        whiteLevelValue;
  3027.     unsigned short                blackLevelValue;
  3028.     VideoDigitizerError            vdigErr = noErr;
  3029.  
  3030.     // Get our VDig data.
  3031.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  3032.  
  3033.     // Get our driver data.
  3034.     pFWCCMDriverData = pFWCCMVDigData->pFWCCMDriverData;
  3035.  
  3036.     // Get the black level value.
  3037.     vdigGetBlackLevelValueParams.pBlackLevelValue = &blackLevelValue;
  3038.     vdigErr =
  3039.         FWCCMGetBlackLevelValue (componentSpecificData, &vdigGetBlackLevelValueParams);
  3040.  
  3041.     // Read the min/max value for the white balance register.
  3042.     if (vdigErr == noErr)
  3043.     {
  3044.         asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  3045.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  3046.                                         0x0000FFFF,
  3047.                                         pFWCCMDriverData->regBaseAddress + 0x050C,
  3048.                                         (Ptr) &fwCCMReg,
  3049.                                         4);
  3050.  
  3051.         vdigErr = FWRead (asynchCommandObjectID);
  3052.         minValue = (fwCCMReg & 0x00FFF000) >> 12;
  3053.         maxValue = fwCCMReg & 0x0FFF;
  3054.     }
  3055.  
  3056.     // Scale white level value.
  3057.     if (vdigErr == noErr)
  3058.     {
  3059.         pWhiteLevelValue = pVDigSetWhiteLevelValueParams->pWhiteLevelValue;
  3060.         blackLevelValue =
  3061.             minValue + (((blackLevelValue)*(maxValue - minValue)) >> 16);
  3062.         whiteLevelValue =
  3063.             minValue + (((*pWhiteLevelValue)*(maxValue - minValue)) >> 16);
  3064.     }
  3065.  
  3066.     // Write the white balance register in the camera.
  3067.     if (vdigErr == noErr)
  3068.     {
  3069.         fwCCMReg = 0x82000000 |
  3070.                    (blackLevelValue << 12) |
  3071.                    whiteLevelValue;
  3072.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  3073.                                         0x0000FFFF,
  3074.                                         pFWCCMDriverData->regBaseAddress + 0x080C,
  3075.                                         (Ptr) &fwCCMReg,
  3076.                                         4);
  3077.  
  3078.         FWCCMDelayForHardware (100*durationMillisecond);
  3079.         vdigErr = FWWrite (asynchCommandObjectID);
  3080.     }
  3081.  
  3082.     return vdigErr;
  3083. }
  3084.  
  3085.  
  3086. ////////////////////////////////////////////////////////////////////////////////
  3087. //
  3088. // FWCCMGetWhiteLevelValue
  3089. //
  3090. //   This function gets the white level for the camera.
  3091. //zzz actually, it gets the V part of the white balance
  3092. //
  3093.  
  3094. static pascal VideoDigitizerError    FWCCMGetWhiteLevelValue(
  3095.     Handle                        componentSpecificData,
  3096.     VDigGetWhiteLevelValueParamsPtr
  3097.                                 pVDigGetWhiteLevelValueParams)
  3098. {
  3099.     FWCCMVDigDataPtr            pFWCCMVDigData;
  3100.     FWCCMDriverDataPtr            pFWCCMDriverData;
  3101.     FWCommandObjectID            asynchCommandObjectID;
  3102.     UInt32                        fwCCMReg;
  3103.     UInt32                        minValue,
  3104.                                 maxValue;
  3105.     VideoDigitizerError            vdigErr = noErr;
  3106.  
  3107.     // Get our VDig data.
  3108.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  3109.  
  3110.     // Get our driver data.
  3111.     pFWCCMDriverData = pFWCCMVDigData->pFWCCMDriverData;
  3112.  
  3113.     // Read the min/max value for the hue register.
  3114.     asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  3115.     FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  3116.                                     0x0000FFFF,
  3117.                                     pFWCCMDriverData->regBaseAddress + 0x050C,
  3118.                                     (Ptr) &fwCCMReg,
  3119.                                     4);
  3120.  
  3121.     vdigErr = FWRead (asynchCommandObjectID);
  3122.     minValue = (fwCCMReg & 0x00FFF000) >> 12;
  3123.     maxValue = fwCCMReg & 0x0FFF;
  3124.  
  3125.     // Read the hue register in the camera.
  3126.     if (vdigErr == noErr)
  3127.     {
  3128.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  3129.                                         0x0000FFFF,
  3130.                                         pFWCCMDriverData->regBaseAddress + 0x080C,
  3131.                                         (Ptr) &fwCCMReg,
  3132.                                         4);
  3133.  
  3134.         vdigErr = FWRead (asynchCommandObjectID);
  3135.     }
  3136.  
  3137.     // Return scaled result.
  3138.     if (vdigErr == noErr)
  3139.     {
  3140.         *(pVDigGetWhiteLevelValueParams->pWhiteLevelValue) =
  3141.             (((fwCCMReg & 0x0FFF) - minValue) << 16) / (maxValue - minValue);
  3142.     }
  3143.  
  3144.     return vdigErr;
  3145. }
  3146.  
  3147.  
  3148. ////////////////////////////////////////////////////////////////////////////////
  3149. //
  3150. // FWCCMGetNumberOfInputs
  3151. //
  3152. //   This routine returns the number of inputs supported by the VDig.
  3153. //
  3154.  
  3155. static pascal VideoDigitizerError    FWCCMGetNumberOfInputs(
  3156.     Handle                        componentSpecificData,
  3157.     VDigGetNumberOfInputsParamsPtr
  3158.                                 pVDigGetNumberOfInputsParams)
  3159. {
  3160.     VideoDigitizerError            vdigErr = noErr;
  3161.  
  3162.     // We only support one input.
  3163.     *(pVDigGetNumberOfInputsParams->pNumInputs) = 0;
  3164.  
  3165.     return vdigErr;
  3166. }
  3167.  
  3168.  
  3169. ////////////////////////////////////////////////////////////////////////////////
  3170. //
  3171. // FWCCMGetInput
  3172. //
  3173. //   This function returns data that identifies the currently active input
  3174. // video source.
  3175. //
  3176.  
  3177. static pascal VideoDigitizerError    FWCCMGetInput(
  3178.     Handle                        componentSpecificData,
  3179.     VDigGetInputParamsPtr        pVDigGetInputParams)
  3180. {
  3181.     VideoDigitizerError            vdigErr = noErr;
  3182.  
  3183.     // We only support one input, so it's the one.
  3184.     *(pVDigGetInputParams->pInput) = 0;
  3185.  
  3186.     return vdigErr;
  3187. }
  3188.  
  3189.  
  3190. ////////////////////////////////////////////////////////////////////////////////
  3191. //
  3192. // FWCCMSetInputStandard
  3193. //
  3194. //   This routine returns the number of inputs supported by the VDig.
  3195. //
  3196.  
  3197. static pascal VideoDigitizerError    FWCCMSetInputStandard(
  3198.     Handle                        componentSpecificData,
  3199.     VDigSetInputStandardParamsPtr
  3200.                                 pVDigSetInputStandardParams)
  3201. {
  3202.     VideoDigitizerError            vdigErr = noErr;
  3203.  
  3204.     // We only support NTSC.
  3205.     //zzz Well we're really just faking it anyway.
  3206.     if ((pVDigSetInputStandardParams->inputStandard) != ntscIn)
  3207.         vdigErr = qtParamErr;
  3208.  
  3209.     return vdigErr;
  3210. }
  3211.  
  3212.  
  3213. ////////////////////////////////////////////////////////////////////////////////
  3214. //
  3215. // FWCCMSetupBuffers
  3216. //
  3217. //   This function defines the output buffers to use with asynchronous grabs.
  3218. //   This is called before we begin recording video (in Premiere, etc.)
  3219. //zzz need to allocate and copy matrix.
  3220. //zzz This undoes sync grab set up unless called from sync grab set up.
  3221. //
  3222.  
  3223. static pascal VideoDigitizerError    FWCCMSetupBuffers(
  3224.     Handle                        componentSpecificData,
  3225.     VDigSetupBuffersParamsPtr    pVDigSetupBuffersParams)
  3226. {
  3227.     FWCCMDriverDataPtr            pFWCCMDriverData;
  3228.     FWCCMVDigDataPtr            pFWCCMVDigData;
  3229.     VdigBufferRecListHandle        bufferList;
  3230.     FWCommandObjectID            asynchCommandObjectID;
  3231.     FWCommandObjectID            isochChannelCommandObjectID;
  3232.     VdigBufferRecListPtr        pVdigBufferRecList = nil;
  3233.     VdigBufferRec                *pVdigBufferRec;
  3234.     VdigBufferRecQElemPtr        pVdigBufferRecQElemList = nil;
  3235.     VdigBufferRecQElemPtr        pVdigBufferRecQElem;
  3236.     UInt32                        numBuffers;
  3237.     UInt32                        bufferListSize;
  3238.     UInt32                        fwCCMReg;
  3239.     UInt32                        i;
  3240.     VideoDigitizerError            vdigErr = noErr;
  3241.  
  3242.     // Get buffer list from params.
  3243.     bufferList = pVDigSetupBuffersParams->bufferList;
  3244.  
  3245.     // Release current buffers.
  3246.     FWCCMReleaseAsyncBuffers (componentSpecificData);
  3247.  
  3248.     // Get our VDig data.
  3249.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  3250.  
  3251.     // Get our driver data.
  3252.     pFWCCMDriverData = pFWCCMVDigData->pFWCCMDriverData;
  3253.  
  3254.     // Get number of buffers.
  3255.     numBuffers = (*bufferList)->count;
  3256.  
  3257.     // Allocate memory for our copy of buffer list.
  3258.     bufferListSize =
  3259.         sizeof (VdigBufferRecList) + (numBuffers - 1) * sizeof (VdigBufferRec);
  3260.     pVdigBufferRecList =
  3261.         (VdigBufferRecListPtr) PoolAllocateResident (bufferListSize, true);
  3262.     if (pVdigBufferRecList != nil)
  3263.     {
  3264.         pVdigBufferRecList->count = (*bufferList)->count;
  3265.     }
  3266.     else
  3267.     {
  3268.         vdigErr = memFullErr;
  3269.     }
  3270.  
  3271.     // Allocate memory for and copy pix maps.
  3272.     for (i = 0; ((i < numBuffers) && (vdigErr == noErr)); i++)
  3273.     {
  3274.         pVdigBufferRec = &(pVdigBufferRecList->list[i]);
  3275.         pVdigBufferRec->dest = (PixMapHandle) NewHandleClear (sizeof (PixMap));
  3276.         if (pVdigBufferRec->dest != nil)
  3277.         {
  3278.             BlockCopy (*((*bufferList)->list[i].dest),
  3279.                        *(pVdigBufferRec->dest),
  3280.                        sizeof (PixMap));
  3281.             pVdigBufferRec->location = (*bufferList)->list[i].location;
  3282.         }
  3283.         else
  3284.         {
  3285.             vdigErr = memFullErr;
  3286.         }
  3287.     }
  3288.  
  3289.     // Allocate memory for queue elements for buffers.
  3290.     if (vdigErr == noErr)
  3291.     {
  3292.         pVdigBufferRecQElemList = (VdigBufferRecQElemPtr)
  3293.             PoolAllocateResident (numBuffers * sizeof (VdigBufferRecQElem), true);
  3294.         if (pVdigBufferRecQElemList != nil)
  3295.         {
  3296.             // Fill in queue elements.
  3297.             pVdigBufferRecQElem = pVdigBufferRecQElemList;
  3298.             pVdigBufferRec = &(pVdigBufferRecList->list[0]);
  3299.             for (i = 0; i < numBuffers; i++)
  3300.             {
  3301.                 pVdigBufferRecQElem->pVdigBufferRec = pVdigBufferRec++;
  3302.                 pVdigBufferRecQElem++;
  3303.             }
  3304.         }
  3305.         else
  3306.         {
  3307.             vdigErr = memFullErr;
  3308.         }
  3309.     }
  3310.  
  3311.     // Set up isochronous channels.
  3312.     //zzz should clean this up on error.
  3313.     if (vdigErr == noErr)
  3314.     {
  3315.         // Set up DCL program.
  3316.  
  3317.         // Reset the jumps and set the callprocs:
  3318.         FWCCMSetupDCLProgram (pFWCCMVDigData,
  3319.                               (DCLCallCommandProcPtr) FWCCMAsyncGrabIsochHandler);
  3320.  
  3321.         // Set start of DCL program.
  3322.         vdigErr = FWSetDCLProgramStart (pFWCCMVDigData->dclProgramID,
  3323.                                         pFWCCMVDigData->dclList);
  3324.     
  3325.         // Initialize isochronous channel.
  3326.         isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  3327.         FWSetFWCommandParams (isochChannelCommandObjectID,
  3328.                               kInvalidFWReferenceID,
  3329.                               kFWCommandSyncFlag,
  3330.                               nil,
  3331.                               0);
  3332.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  3333.                                                 pFWCCMVDigData->isochChannelID);
  3334.  
  3335.         vdigErr = FWInitializeIsochronousChannel (isochChannelCommandObjectID);
  3336.     }
  3337.  
  3338.     // Channel has now been initialized.
  3339.     if (vdigErr == noErr)
  3340.     {
  3341.         pFWCCMVDigData->channelInitialized = true;
  3342.         pFWCCMVDigData->asynchMode = true;
  3343.     }
  3344.  
  3345.     // Set camera to 30 fps.
  3346.     if (vdigErr == noErr)
  3347.     {
  3348.         fwCCMReg = 0x80000000;
  3349.         asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  3350.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  3351.                                         0x0000FFFF,
  3352.                                         pFWCCMDriverData->regBaseAddress + 0x0600,
  3353.                                         (Ptr) &fwCCMReg,
  3354.                                         4);
  3355.  
  3356.         FWCCMDelayForHardware (100*durationMillisecond);
  3357.         vdigErr = FWWrite (asynchCommandObjectID);
  3358.     }
  3359.  
  3360.     // Start up isochronous channel.
  3361.     //zzz do this in FWCCMGrabOneFrameAsync???
  3362.     if (vdigErr == noErr)
  3363.     {
  3364.         isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  3365.         FWSetFWCommandParams (isochChannelCommandObjectID,
  3366.                               kInvalidFWReferenceID,
  3367.                               kFWCommandSyncFlag,
  3368.                               nil,
  3369.                               0);
  3370.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  3371.                                                 pFWCCMVDigData->isochChannelID);
  3372.  
  3373.         pFWCCMVDigData->channelActive = true;
  3374.         vdigErr = FWStartIsochronousChannel (isochChannelCommandObjectID);
  3375.     }
  3376.  
  3377.     // Fill in FWCCM VDig data.
  3378.     if (vdigErr == noErr)
  3379.     {
  3380.         pFWCCMVDigData->pVdigBufferRecList = pVdigBufferRecList;
  3381.         pFWCCMVDigData->pVdigBufferRecQElemList = pVdigBufferRecQElemList;
  3382.     }
  3383.  
  3384.     // Clean up on error.
  3385.     if (vdigErr != noErr)
  3386.     {
  3387.         if (pVdigBufferRecList != nil)
  3388.             PoolDeallocate ((Ptr) pVdigBufferRecList);
  3389.  
  3390.         if (pVdigBufferRecQElemList != nil)
  3391.             PoolDeallocate ((Ptr) pVdigBufferRecQElemList);
  3392.     }
  3393.  
  3394.     return vdigErr;
  3395. }
  3396.  
  3397.  
  3398. ////////////////////////////////////////////////////////////////////////////////
  3399. //
  3400. // FWCCMGrabOneFrameAsync
  3401. //
  3402. //   This function starts digitizing asynchronously a single frame of video.
  3403. //   I believe this is called for each frame, but since we leave the DCL program
  3404. //   running all the time there isn't anything for us to do now.
  3405. //
  3406.  
  3407. static pascal VideoDigitizerError    FWCCMGrabOneFrameAsync(
  3408.     Handle                        componentSpecificData,
  3409.     VDigGrabOneFrameAsyncParamsPtr
  3410.                                 pVDigGrabOneFrameAsyncParams)
  3411. {
  3412.     VideoDigitizerError            vdigErr = noErr;
  3413.  
  3414.     return vdigErr;
  3415. }
  3416.  
  3417.  
  3418. ////////////////////////////////////////////////////////////////////////////////
  3419. //
  3420. // FWCCMDone
  3421. //
  3422. //   This function returns a non-zero value if the FWCCMGrabOneFrameAsync
  3423. // function is finished with the specified output buffer.  Otherwise, this
  3424. // function returns zero.
  3425. //
  3426.  
  3427. static pascal long    FWCCMDone(
  3428.     Handle                        componentSpecificData,
  3429.     VDigDoneParamsPtr            pVDigDoneParams)
  3430. {
  3431.     FWCCMVDigDataPtr            pFWCCMVDigData;
  3432.     VdigBufferRecQElemPtr        pVdigBufferRecQElemList;
  3433.     VdigBufferRecQElemPtr        pVdigBufferRecQElem;
  3434.     short                        buffer;
  3435.     UInt32                        numBuffers, bufferNum;
  3436.     UInt32                        i;
  3437.  
  3438.     // Get buffer from parameters.
  3439.     buffer = pVDigDoneParams->buffer;
  3440.  
  3441.     // Get our VDig data.
  3442.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  3443.  
  3444.     // Get our list of buffer queue elements.
  3445.     pVdigBufferRecQElemList = pFWCCMVDigData->pVdigBufferRecQElemList;
  3446.  
  3447.     // Queue up all buffers not in use in order starting from buffer.
  3448.     numBuffers = pFWCCMVDigData->pVdigBufferRecList->count;
  3449.     for (i = 0; i < numBuffers; i++)
  3450.     {
  3451.         // Get next buffer in line.
  3452.         bufferNum = (i + buffer) % numBuffers;
  3453.         pVdigBufferRecQElem =
  3454.             &(pFWCCMVDigData->pVdigBufferRecQElemList[bufferNum]);
  3455.  
  3456.         // Add it to queue if it's not in use.
  3457.         if (!pVdigBufferRecQElem->inUse)
  3458.         {
  3459.             // Buffer is now in use and not done.
  3460.             pVdigBufferRecQElem->inUse = true;
  3461.             pVdigBufferRecQElem->done = false;
  3462.     
  3463.             // Queue it up.
  3464.             PBEnqueueLast ((QElemPtr) pVdigBufferRecQElem,
  3465.                            pFWCCMVDigData->vdigBufferRecQueue);
  3466.         }
  3467.     }
  3468.  
  3469.     // If buffer is done, take it out of use.
  3470.     if (pVdigBufferRecQElemList[buffer].done)
  3471.         pVdigBufferRecQElemList[buffer].inUse = false;
  3472.  
  3473.     return (volatile long) pVdigBufferRecQElemList[buffer].done;
  3474. }
  3475.  
  3476.  
  3477. ////////////////////////////////////////////////////////////////////////////////
  3478. //
  3479. // FWCCMSetFrameRate
  3480. //
  3481. //   This function sets the desired frame rate.
  3482. //zzz implement this for real.
  3483. //
  3484.  
  3485. static pascal long    FWCCMSetFrameRate(
  3486.     Handle                        componentSpecificData,
  3487.     VDigSetFrameRateParamsPtr    pVDigSetFrameRateParams)
  3488. {
  3489.     VideoDigitizerError            vdigErr = noErr;
  3490.  
  3491.     return vdigErr;
  3492. }
  3493.  
  3494.  
  3495. ////////////////////////////////////////////////////////////////////////////////
  3496. //
  3497. // FWCCMReleaseAsyncBuffers
  3498. //
  3499. //   This function returns a non-zero value if the FWCCMGrabOneFrameAsync
  3500. // function is finished with the specified output buffer.  Otherwise, this
  3501. // function returns zero.
  3502. //
  3503.  
  3504. static pascal VideoDigitizerError    FWCCMReleaseAsyncBuffers(
  3505.     Handle                        componentSpecificData)
  3506. {
  3507.     FWCCMDriverDataPtr            pFWCCMDriverData;
  3508.     FWCCMVDigDataPtr            pFWCCMVDigData;
  3509.     FWCommandObjectID            asynchCommandObjectID;
  3510.     FWCommandObjectID            isochChannelCommandObjectID;
  3511.     VdigBufferRecListPtr        pVdigBufferRecList;
  3512.     VdigBufferRecQElemPtr        pVdigBufferRecQElemList;
  3513.     UInt32                        fwCCMReg;
  3514.     UInt32                        i;
  3515.     VideoDigitizerError            vdigErr = noErr;
  3516.  
  3517.     // Get our VDig data.
  3518.     pFWCCMVDigData = (FWCCMVDigDataPtr) *componentSpecificData;
  3519.  
  3520.     // Get our driver data.
  3521.     pFWCCMDriverData = pFWCCMVDigData->pFWCCMDriverData;
  3522.  
  3523.     // Release isochronous channel.
  3524.     if (pFWCCMVDigData->channelInitialized)
  3525.     {
  3526.         isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  3527.         FWSetFWCommandParams (isochChannelCommandObjectID,
  3528.                               kInvalidFWReferenceID,
  3529.                               kFWCommandSyncFlag,
  3530.                               nil,
  3531.                               0);
  3532.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  3533.                                                 pFWCCMVDigData->isochChannelID);
  3534.  
  3535.         pFWCCMVDigData->channelActive = false;
  3536.         FWStopIsochronousChannel (isochChannelCommandObjectID);
  3537.  
  3538.         isochChannelCommandObjectID = pFWCCMVDigData->isochChannelCommandObjectID;
  3539.         FWSetFWCommandParams (isochChannelCommandObjectID,
  3540.                               kInvalidFWReferenceID,
  3541.                               kFWCommandSyncFlag,
  3542.                               nil,
  3543.                               0);
  3544.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  3545.                                                 pFWCCMVDigData->isochChannelID);
  3546.  
  3547.         FWReleaseIsochronousChannel (isochChannelCommandObjectID);
  3548.     }
  3549.  
  3550.     // Channel is no longer initialized.
  3551.     pFWCCMVDigData->channelInitialized = false;
  3552.     pFWCCMVDigData->asynchMode = false;
  3553.  
  3554.     // Set camera to 30 fps.
  3555.     if (vdigErr == noErr)
  3556.     {
  3557.         fwCCMReg = 0x80000000;
  3558.         asynchCommandObjectID = pFWCCMVDigData->asynchCommandObjectID;
  3559.         FWSetCommonAsynchCommandParams (asynchCommandObjectID,
  3560.                                         0x0000FFFF,
  3561.                                         pFWCCMDriverData->regBaseAddress + 0x0600,
  3562.                                         (Ptr) &fwCCMReg,
  3563.                                         4);
  3564.  
  3565.         FWCCMDelayForHardware (100*durationMillisecond);
  3566.         vdigErr = FWWrite (asynchCommandObjectID);
  3567.     }
  3568.  
  3569.     // Deallocate buffer rec list.
  3570.     pVdigBufferRecList = pFWCCMVDigData->pVdigBufferRecList;
  3571.     if (pVdigBufferRecList != nil)
  3572.     {
  3573.         for (i = 0; i < pVdigBufferRecList->count; i++)
  3574.         {
  3575.             if (pVdigBufferRecList->list[i].dest != nil)
  3576.                 DisposeHandle ((Handle) pVdigBufferRecList->list[i].dest);
  3577.         }
  3578.  
  3579.         PoolDeallocate ((Ptr) pVdigBufferRecList);
  3580.         pFWCCMVDigData->pVdigBufferRecList = nil;
  3581.     }
  3582.  
  3583.     // Deallocate queue for buffers.
  3584.     pVdigBufferRecQElemList = pFWCCMVDigData->pVdigBufferRecQElemList;
  3585.     if (pVdigBufferRecQElemList != nil)
  3586.     {
  3587.         PoolDeallocate ((Ptr) pVdigBufferRecQElemList);
  3588.         pFWCCMVDigData->pVdigBufferRecQElemList = nil;
  3589.     }
  3590.  
  3591.     // Initialize vdig buffer queue.
  3592.     PBQueueInit (pFWCCMVDigData->vdigBufferRecQueue);
  3593.  
  3594.     return vdigErr;
  3595. }
  3596.  
  3597.  
  3598. ////////////////////////////////////////////////////////////////////////////////
  3599. //
  3600. // FWCCMCopyToDestPixMap
  3601. //
  3602. //   This routine converts the camera data in the conversion buffer to RGB and
  3603. // copies it into the dest pix map set by FWCCMSetPlayThruDestination.
  3604. // Note however that this is not used with playthrough.
  3605. //
  3606. // Currently hardwired to 4:2:2 30fps
  3607.  
  3608. static void    FWCCMCopyToDestPixMap(
  3609.     FWCCMVDigDataPtr            pFWCCMVDigData)
  3610. {
  3611.     PixMapHandle                hDestPixMap;
  3612.     UInt32                        *pSrc;
  3613.     Ptr                            pDstRow;
  3614.     UInt32                        rowBytes;
  3615.     UInt32                        pixelBytes;
  3616.     UInt32                        i;
  3617.     DCLTransferPacketPtr        pDCLCommand;
  3618.     UInt32                        frameNum;
  3619.  
  3620.     // Get some vdig parameters.
  3621.     hDestPixMap = pFWCCMVDigData->hDestPixMap;
  3622.  
  3623.     // Convert YUV 4:2:2 to RGB and copy to dest pix map.
  3624.     rowBytes = (*hDestPixMap)->rowBytes & 0x7FFF;
  3625.     pixelBytes = (*hDestPixMap)->pixelSize >> 3;
  3626.  
  3627.     // zzz this isn't really right in the pixel-double case, but it works (always 0, 0)
  3628.     pDstRow = (*hDestPixMap)->baseAddr +
  3629.               pFWCCMVDigData->destRect.top*rowBytes +
  3630.               pFWCCMVDigData->destRect.left*pixelBytes;
  3631.  
  3632.     frameNum = pFWCCMVDigData->pendingFrameNum;
  3633.     pDCLCommand = pFWCCMVDigData->firstDCLTransferPacket[frameNum];
  3634.  
  3635.     for (i = 0; i < 240; i++)
  3636.     {
  3637.         pSrc = ((UInt32 *) pDCLCommand->buffer) + 1;        // skip header
  3638.  
  3639.         if ((pFWCCMVDigData->destRect.right - pFWCCMVDigData->destRect.left) == 640 &&
  3640.             (pFWCCMVDigData->destRect.bottom - pFWCCMVDigData->destRect.top) == 480)
  3641.         {
  3642.             if ((*hDestPixMap)->pixelSize == 16)
  3643.             {
  3644.                 // zzz what if 411?
  3645.                 FWCCMConvertYUV422ToRGB16Double (pFWCCMVDigData, pSrc, 640, (UInt32 *) pDstRow, rowBytes);
  3646.             }
  3647.             else if ((*hDestPixMap)->pixelSize == 32)
  3648.             {
  3649.                 // zzz what if 411?
  3650.                 FWCCMConvertYUV422ToRGB32Double (pFWCCMVDigData, pSrc, 640, (UInt32 *) pDstRow, rowBytes);
  3651.             }
  3652.             pDstRow += (rowBytes * 2);
  3653.         }
  3654.         else // assume 320 x 240
  3655.         {
  3656.             if ((*hDestPixMap)->pixelSize == 16)
  3657.             {
  3658.                 FWCCMConvertYUV422ToRGB16 (pFWCCMVDigData, pSrc, 640, (UInt32 *) pDstRow, rowBytes);
  3659.             }
  3660.             else if ((*hDestPixMap)->pixelSize == 32)
  3661.             {
  3662.                 FWCCMConvertYUV422ToRGB32 (pFWCCMVDigData, pSrc, 640, (UInt32 *) pDstRow, rowBytes);
  3663.             }
  3664.             pDstRow += rowBytes;
  3665.         }
  3666.  
  3667.         // Go to next packet
  3668.         pDCLCommand = (DCLTransferPacketPtr) pDCLCommand->pNextDCLCommand;
  3669.     }
  3670.  
  3671.     // Do next frame next time
  3672.     pFWCCMVDigData->pendingFrameNum = (frameNum + 1) % kNumFrameBufs;
  3673.  
  3674.     // One less frame waiting
  3675.     DecrementAtomic ((SInt32 *) &(pFWCCMVDigData->pendingFrameCount));
  3676.  
  3677.     // Now put the frame we used up on the end of the list
  3678.     FWCCMSetDCLProgramEndFrame (pFWCCMVDigData, frameNum);
  3679. }
  3680.  
  3681.  
  3682. ////////////////////////////////////////////////////////////////////////////////
  3683. //
  3684. // FWCCMAsyncGrabIsochHandler
  3685. //
  3686. //   This routine handles the isochronous buffers for the async grab calls.
  3687. //
  3688.  
  3689. static void    FWCCMAsyncGrabIsochHandler(
  3690.     DCLCommandPtr                pDCLCommandPtr)
  3691. {
  3692.     FWCCMVDigDataPtr            pFWCCMVDigData;
  3693.     VdigBufferRecQElemPtr        pVdigBufferRecQElem;
  3694.     DCLCallProcPtr                pDCLCallProc;
  3695.     DCLTransferPacketPtr        pDCLCommand;
  3696.     UInt32                        packetHeader;
  3697.     UInt32                        packetSize;
  3698.     UInt32                        syncBits;
  3699.     UInt32                        packetNum;
  3700.     UInt32                        frameNum;
  3701.     OSStatus                    status = noErr;
  3702.  
  3703.     // Recast DCL command;
  3704.     pDCLCallProc = (DCLCallProcPtr) pDCLCommandPtr;
  3705.  
  3706.     // Get data.
  3707.     pFWCCMVDigData = (FWCCMVDigDataPtr) pDCLCallProc->procData;
  3708.  
  3709.     // Note, probably want to break this up - will need to be more async.
  3710.     frameNum = pFWCCMVDigData->pendingFrameNum;
  3711.     pDCLCommand = pFWCCMVDigData->firstDCLTransferPacket[frameNum];
  3712.  
  3713.     // Convert packets and send to destination pix map.
  3714.     for (packetNum = 0; packetNum < kNumPacketsPerFrameBuf; packetNum++)
  3715.     {
  3716.         // Get packet size and sync bits.
  3717.         packetHeader = *((UInt32 *) (pDCLCommand->buffer));
  3718.         packetSize = (packetHeader & kFWIsochDataLength) >>
  3719.                      kFWIsochDataLengthPhase;
  3720.         syncBits = (packetHeader & kFWIsochSy) >> kFWIsochSyPhase;
  3721.  
  3722.         // Get vdig buffer at head of queue.
  3723.         //zzz maybe we should dequeue it into a vdigdata field before using it.
  3724.         if (status == noErr)
  3725.         {
  3726.             pVdigBufferRecQElem = (VdigBufferRecQElemPtr)
  3727.                                     pFWCCMVDigData->vdigBufferRecQueue->qHead;
  3728.             if (pVdigBufferRecQElem == nil)
  3729.             {
  3730.                 // No buffer queued to write into, so skip rest of packets.
  3731.                 packetNum = kNumPacketsPerFrameBuf;
  3732.                 status = -1;
  3733.             }
  3734.         }
  3735.  
  3736.         // Reset current location if this is the first packet of a frame.
  3737.         if ((status == noErr) &&
  3738.              ((syncBits == 1) || (pVdigBufferRecQElem->currentLocation.v == 240)))
  3739.         {
  3740.             pVdigBufferRecQElem->currentLocation.v = 0;
  3741.             pVdigBufferRecQElem->currentLocation.h = 0;
  3742.         }
  3743.  
  3744.         // Grab part of the frame.
  3745.         if (status == noErr)
  3746.         {
  3747.             FWCCMCopyIsochChannelToVdigBuffer
  3748.                 (pFWCCMVDigData, pDCLCommand, pVdigBufferRecQElem);
  3749.         }
  3750.  
  3751.         // Check if we have a complete frame.
  3752.         if (status == noErr)
  3753.         {
  3754.             if (pVdigBufferRecQElem->currentLocation.v == 240)
  3755.             {
  3756.                 // Get next vdig buffer from queue.
  3757.                 if (status == noErr)
  3758.                 {
  3759.                     PBDequeueFirst (pFWCCMVDigData->vdigBufferRecQueue,
  3760.                                     (QElemPtr *) &pVdigBufferRecQElem);
  3761.                     if (pVdigBufferRecQElem == nil)
  3762.                         status = -1;
  3763.                 }
  3764.  
  3765.                 // Buffer is done.
  3766.                 if (status == noErr)
  3767.                 {
  3768.                     pVdigBufferRecQElem->done = true;
  3769.                     pVdigBufferRecQElem->currentLocation.v = 0;
  3770.                     pVdigBufferRecQElem->currentLocation.h = 0;
  3771.                 }
  3772.             }
  3773.         }
  3774.  
  3775.         // Update for next packet.
  3776.         pDCLCommand = (DCLTransferPacketPtr) pDCLCommand->pNextDCLCommand;
  3777.     }
  3778.  
  3779.     // We finished with the frame - now put it at the end of the DCL program:
  3780.  
  3781.     // zzz Question:  Is it safe to call ModifyJump (done next) if the program
  3782.     // was terminated while we did the image processing above? 
  3783.  
  3784.     // We're done with this frame, so make it available at the end of the program.
  3785.     FWCCMSetDCLProgramEndFrame (pFWCCMVDigData, frameNum);
  3786.  
  3787.     // Next time, do the next frame:
  3788.     pFWCCMVDigData->pendingFrameNum = (frameNum + 1) % kNumFrameBufs;
  3789.  
  3790. }
  3791.  
  3792.  
  3793. ////////////////////////////////////////////////////////////////////////////////
  3794. //
  3795. // FWCCMCopyIsochChannelToVdigBuffer
  3796. //
  3797. //   This routine converts the camera data in the DCL transfer packet to RGB
  3798. // and copies it into the pix map specified in the VdigBufferRec.
  3799. //zzz assumes channel buffer length is a multiple of 4.
  3800. //
  3801.  
  3802. static void    FWCCMCopyIsochChannelToVdigBuffer(
  3803.     FWCCMVDigDataPtr            pFWCCMVDigData,
  3804.     DCLTransferPacketPtr        pDCLTransferPacket,
  3805.     VdigBufferRecQElemPtr        pVdigBufferRecQElem)
  3806. {
  3807.     VdigBufferRec                *pVdigBufferRec;
  3808.     PixMapHandle                hDestPixMap;
  3809.     UInt32                        *pSrc;
  3810.     Ptr                            pDstRow;
  3811.     UInt32                        *pDst;
  3812.     UInt32                        packetHeader;
  3813.     UInt32                        rowBytes;
  3814.     UInt32                        pixelBytes;
  3815.     Point                        baseLocation,
  3816.                                 currentLocation;
  3817.     UInt32                        bufferSize;
  3818.  
  3819.     // Get some vdig parameters.
  3820.     pVdigBufferRec = pVdigBufferRecQElem->pVdigBufferRec;
  3821.     hDestPixMap = pVdigBufferRec->dest;
  3822.  
  3823.     // Convert YUV 4:2:2 to RGB and copy to dest pix map.
  3824.     rowBytes = (*hDestPixMap)->rowBytes & 0x7FFF;
  3825.     pixelBytes = (*hDestPixMap)->pixelSize >> 3;
  3826.     pSrc = ((UInt32 *) pDCLTransferPacket->buffer) + 1;
  3827.     baseLocation = pVdigBufferRec->location;
  3828.     currentLocation = pVdigBufferRecQElem->currentLocation;
  3829.     packetHeader = *((UInt32 *) (pDCLTransferPacket->buffer));
  3830.     bufferSize = (packetHeader & kFWIsochDataLength) >> kFWIsochDataLengthPhase;
  3831.  
  3832.     if ((pFWCCMVDigData->destRect.right - pFWCCMVDigData->destRect.left) == 640 &&
  3833.         (pFWCCMVDigData->destRect.bottom - pFWCCMVDigData->destRect.top) == 480)
  3834.     {
  3835.         pDstRow = (*hDestPixMap)->baseAddr +
  3836.                   (baseLocation.v + (currentLocation.v * 2) - (*hDestPixMap)->bounds.top) * rowBytes +
  3837.                   (baseLocation.h - (*hDestPixMap)->bounds.left) * pixelBytes;
  3838.         pDst = (UInt32 *) pDstRow + (currentLocation.h * 2) * pixelBytes;
  3839.  
  3840.         // zzz what if 411?
  3841.         if ((*hDestPixMap)->pixelSize == 16)
  3842.             FWCCMConvertYUV422ToRGB16Double (pFWCCMVDigData, pSrc, bufferSize, pDst, rowBytes);
  3843.     
  3844.         // zzz what if 411?
  3845.         if ((*hDestPixMap)->pixelSize == 32)
  3846.             FWCCMConvertYUV422ToRGB32Double (pFWCCMVDigData, pSrc, bufferSize, pDst, rowBytes);
  3847.     }
  3848.     else        // 320 x 240
  3849.     {
  3850.         pDstRow = (*hDestPixMap)->baseAddr +
  3851.                   (baseLocation.v + currentLocation.v - (*hDestPixMap)->bounds.top) * rowBytes +
  3852.                   (baseLocation.h - (*hDestPixMap)->bounds.left) * pixelBytes;
  3853.         pDst = (UInt32 *) pDstRow + currentLocation.h * pixelBytes;
  3854.  
  3855.         if ((*hDestPixMap)->pixelSize == 16)
  3856.             FWCCMConvertYUV422ToRGB16 (pFWCCMVDigData, pSrc, bufferSize, pDst, rowBytes);
  3857.     
  3858.         if ((*hDestPixMap)->pixelSize == 32)
  3859.             FWCCMConvertYUV422ToRGB32 (pFWCCMVDigData, pSrc, bufferSize, pDst, rowBytes);
  3860.     }
  3861.  
  3862.     pVdigBufferRecQElem->currentLocation.v++;
  3863. }
  3864.  
  3865.  
  3866. ////////////////////////////////////////////////////////////////////////////////
  3867. //
  3868. // FWCCMPlayThruIsochHandler
  3869. //
  3870. //   This routine handles the isochronous buffers for play thru.
  3871. //
  3872.  
  3873. static void    FWCCMPlayThruIsochHandler(
  3874.     DCLCommandPtr                pDCLCommandPtr)
  3875. {
  3876.     FWCCMVDigDataPtr            pFWCCMVDigData;
  3877.     DCLCallProcPtr                pDCLCallProc;
  3878.     DCLTransferPacketPtr        pDCLCommand;
  3879.     UInt32                        packetHeader;
  3880.     UInt32                        syncBits;
  3881.     UInt32                        packetNum;
  3882.     UInt32                        frameNum;
  3883.     AbsoluteTime                startTime, endTime, runTime;
  3884.     Duration                    duration;
  3885.     OSStatus                    status = noErr;
  3886.  
  3887. //    DebugStrStatus ((ConstStr255Param) "\pFWCCMPlayThruIsochHandler");
  3888.  
  3889.     startTime = UpTime ();
  3890.  
  3891.     // Recast DCL command;
  3892.     pDCLCallProc = (DCLCallProcPtr) pDCLCommandPtr;
  3893.  
  3894.     // Get data
  3895.     pFWCCMVDigData = (FWCCMVDigDataPtr) pDCLCallProc->procData;
  3896.  
  3897.     // Ultimately, we want to do the conversion in chunks.
  3898.     // When we do, make sure we can't queue some work, and stop and restart the
  3899.     // program before the work gets done.  That would be a mess.
  3900.     // For now, do it all at once:
  3901.     frameNum = pFWCCMVDigData->pendingFrameNum;        // not correct if we're async
  3902.     pDCLCommand = pFWCCMVDigData->firstDCLTransferPacket[frameNum];
  3903.  
  3904.     if (pFWCCMVDigData->skipFrameCounter)
  3905.     {
  3906.         pFWCCMVDigData->skipFrameCounter--;
  3907.     }
  3908.     else
  3909.     {
  3910.         // Convert packets and send to destination pix map.
  3911.         for (packetNum = 0; packetNum < kNumPacketsPerFrameBuf; packetNum++)
  3912.         {
  3913.             // Get sync bits.
  3914.             packetHeader = *((UInt32 *) (pDCLCommand->buffer));
  3915.             syncBits = (packetHeader & kFWIsochSy) >> kFWIsochSyPhase;
  3916.     
  3917.             // Set to top of frame if sync bits indicate this packet as the
  3918.             // top of frame (Lynx), or if we've filled up a frame (Lynx/Pele).
  3919.             if ((syncBits == 1) || (pFWCCMVDigData->currentLocation.v == 240))
  3920.             {
  3921.                 pFWCCMVDigData->currentLocation.v = 0;
  3922.                 pFWCCMVDigData->currentLocation.h = 0;
  3923.             }
  3924.     
  3925.             // Transfer packet data to destination pix map.
  3926.             FWCCMCopyIsochChannelToDestPixMap (pFWCCMVDigData, pDCLCommand);
  3927.     
  3928.             // Go to next packet.
  3929.             pDCLCommand = (DCLTransferPacketPtr) pDCLCommand->pNextDCLCommand;
  3930.         }
  3931.     }
  3932.     // zzz Question:  Is it safe to call ModifyJump (done next) if the program
  3933.     // was terminated while we did the image processing above? 
  3934.  
  3935.     // We're done with this frame, so make it available at the end of the program.
  3936.     FWCCMSetDCLProgramEndFrame (pFWCCMVDigData, frameNum);
  3937.  
  3938.     // Check how long the conversion took.  Note that the documentation in
  3939.     // Designing PCI Cards and Drivers seems to be backwards, regarding subtraction
  3940.     endTime = UpTime ();
  3941.     runTime = SubAbsoluteFromAbsolute (endTime, startTime);
  3942.     duration = AbsoluteToDuration (runTime);
  3943.     
  3944.     // Duration could be milliseconds (positive) or microseconds (negative)
  3945.     if (duration < 0)
  3946.         duration = duration / -1000;
  3947.  
  3948.     // 1/30 of a second is 33 milliseconds.  If we spend more than 30 milliseconds
  3949.     // doing this conversion, we might be falling behind.  Conversely, if we spend
  3950.     // less than 25, assume that all is well.  (Times consistently under 31 will
  3951.     // cause no skipping, but a time under 25 will undo any over-30 we recently saw.)
  3952.  
  3953.     if (duration > (durationMillisecond * 30))
  3954.         pFWCCMVDigData->slowFrameCounter++;
  3955.  
  3956.     if (duration < (durationMillisecond * 25))
  3957.         pFWCCMVDigData->slowFrameCounter = 0;
  3958.  
  3959.     // If we have more than 4 slow frames before a fast one, we are probably
  3960.     // saturated (or very close).  To recover, skip the next two frames.  This
  3961.     // makes the image stream bursty, but if we skip only one, the DMA may have
  3962.     // another frame already waiting for us, and we will not recover.
  3963.  
  3964.     if (pFWCCMVDigData->slowFrameCounter > 4)
  3965.     {
  3966.         pFWCCMVDigData->slowFrameCounter = 0;
  3967.         pFWCCMVDigData->skipFrameCounter = 2;
  3968.     }
  3969.  
  3970.     // Next time, do the next frame:
  3971.     pFWCCMVDigData->pendingFrameNum = (frameNum + 1) % kNumFrameBufs;
  3972.  
  3973. }
  3974.  
  3975.  
  3976. ////////////////////////////////////////////////////////////////////////////////
  3977. //
  3978. // FWCCMGrabOneFrameIsochHandler
  3979. //
  3980. //   This routine handles the isochronous buffers for grab one frame.
  3981. //   Generally this is used when we watch video without using playthrough.
  3982. //
  3983.  
  3984. static void    FWCCMGrabOneFrameIsochHandler(
  3985.     DCLCommandPtr                pDCLCommandPtr)
  3986. {
  3987.     FWCCMVDigDataPtr            pFWCCMVDigData;
  3988.     DCLCallProcPtr                pDCLCallProc;
  3989.     OSStatus                    status = noErr;
  3990.  
  3991. //    DebugStrStatus ((ConstStr255Param) "\pFWCCMGrabOneFrameIsochHandler");
  3992.  
  3993.     // Recast DCL command;
  3994.     pDCLCallProc = (DCLCallProcPtr) pDCLCommandPtr;
  3995.  
  3996.     // Get data.
  3997.     pFWCCMVDigData = (FWCCMVDigDataPtr) pDCLCallProc->procData;
  3998.  
  3999.     // Instead of copying the data, just leave it in place.
  4000.     IncrementAtomic ((SInt32 *) &(pFWCCMVDigData->pendingFrameCount));
  4001.  
  4002. }
  4003.  
  4004.  
  4005. ////////////////////////////////////////////////////////////////////////////////
  4006. //
  4007. // FWCCMCopyIsochChannelToDestPixMap
  4008. //
  4009. //   This routine converts the camera data in the DCL transfer packet to RGB
  4010. // and copies it into the dest pix map by FWCCMSetPlayThruDestination.
  4011.  
  4012. static void    FWCCMCopyIsochChannelToDestPixMap(
  4013.     FWCCMVDigDataPtr            pFWCCMVDigData,
  4014.     DCLTransferPacketPtr        pDCLTransferPacket)
  4015. {
  4016.     PixMapHandle                hDestPixMap;
  4017.     Ptr                            pDstRow;
  4018.     UInt32                        *pSrc, *pDst;
  4019.     UInt32                        packetHeader;
  4020.     UInt32                        rowBytes, pixelBytes;
  4021.     Point                        baseLocation, currentLocation;
  4022.     SInt32                        bufferSize;
  4023.  
  4024.     // Get some vdig parameters.
  4025.     hDestPixMap = pFWCCMVDigData->hDestPixMap;
  4026.  
  4027.     // Convert YUV 4:2:2 to RGB and copy to dest pix map.
  4028.     rowBytes = (*hDestPixMap)->rowBytes & 0x7FFF;
  4029.     pixelBytes = (*hDestPixMap)->pixelSize >> 3;
  4030.     pSrc = (UInt32 *) (pDCLTransferPacket->buffer + sizeof (UInt32));
  4031.     packetHeader = *((UInt32 *) (pDCLTransferPacket->buffer));
  4032.     bufferSize = (packetHeader & kFWIsochDataLength) >> kFWIsochDataLengthPhase;
  4033.     baseLocation.h = pFWCCMVDigData->destRect.left;
  4034.     baseLocation.v = pFWCCMVDigData->destRect.top;
  4035.     currentLocation = pFWCCMVDigData->currentLocation;
  4036.  
  4037.     if ((pFWCCMVDigData->destRect.right - pFWCCMVDigData->destRect.left) == 640 &&
  4038.         (pFWCCMVDigData->destRect.bottom - pFWCCMVDigData->destRect.top) == 480)
  4039.     {
  4040.         pDstRow = (*hDestPixMap)->baseAddr +
  4041.               (baseLocation.v + currentLocation.v * 2) * rowBytes +
  4042.               baseLocation.h * pixelBytes;
  4043.         pDst = (UInt32 *) (pDstRow + currentLocation.h * pixelBytes * 2);
  4044.  
  4045.         // zzz what if 411?
  4046.         if ((*hDestPixMap)->pixelSize == 16)
  4047.             FWCCMConvertYUV422ToRGB16Double (pFWCCMVDigData, pSrc, (UInt32) bufferSize, pDst, rowBytes);
  4048.  
  4049.         // zzz what if 411?
  4050.         if ((*hDestPixMap)->pixelSize == 32)
  4051.             FWCCMConvertYUV422ToRGB32Double (pFWCCMVDigData, pSrc, (UInt32) bufferSize, pDst, rowBytes);
  4052.     }
  4053.     else //  assume 320 x 240
  4054.     {
  4055.         pDstRow = (*hDestPixMap)->baseAddr +
  4056.                   (baseLocation.v + currentLocation.v) * rowBytes +
  4057.                   baseLocation.h * pixelBytes;
  4058.         pDst = (UInt32 *) (pDstRow + currentLocation.h * pixelBytes);
  4059.  
  4060.         if ((*hDestPixMap)->pixelSize == 16)
  4061.             FWCCMConvertYUV422ToRGB16 (pFWCCMVDigData, pSrc, (UInt32) bufferSize, pDst, rowBytes);
  4062.     
  4063.         if ((*hDestPixMap)->pixelSize == 32)
  4064.             FWCCMConvertYUV422ToRGB32 (pFWCCMVDigData, pSrc, (UInt32) bufferSize, pDst, rowBytes);
  4065.     }
  4066.  
  4067.     pFWCCMVDigData->currentLocation.v++;
  4068. }
  4069.  
  4070.  
  4071. ////////////////////////////////////////////////////////////////////////////////
  4072. //
  4073. // FWCCMConvertYUV422ToRGB16
  4074. //
  4075. //   This routine converts YUV 4:2:2 data into 16-bit RGB data, presumably in a
  4076. //   pixMap or similar structure.  Only whole scanlines are supported (multiple
  4077. //   scanlines will work).  We use aligned 32-bit writes to the target, as long
  4078. //   as the target is at least 16-bit aligned.
  4079. //
  4080. //   This routine is rather optimized, and that makes it hard to read.  See the
  4081. //   comments in FWCCMConvertYUV422ToRGB32 that apply to the 320x240 case for
  4082. //   some explanation.
  4083.  
  4084. static void    FWCCMConvertYUV422ToRGB16(
  4085.     FWCCMVDigDataPtr            pFWCCMVDigData,
  4086.     UInt32                        *pSrcYUV,            // YUV 4:2:2 Source pointer
  4087.     UInt32                        byteCountYUV,        // Source length in bytes
  4088.     UInt32                        *pDstRGB,            // RGB 16 Destination pointer
  4089.     UInt32                        rowBytesRGB)        // Byte offset to next row of destination
  4090. {
  4091.     UInt32                        *pSrc, *pDstRow, *pDst1, *pDst2;
  4092.     UInt32                        bufferSize, loops;
  4093.     UInt32                        srcYUV, Y1, U, V, Y2, UV;
  4094.     UInt16                        hold;
  4095.     Ptr                            table;
  4096.  
  4097.     pSrc = pSrcYUV;
  4098.     pDstRow = pDstRGB;
  4099.     bufferSize = byteCountYUV;
  4100.     table = (Ptr) pFWCCMVDigData->yuvToRGB16Table;
  4101.  
  4102.     while (bufferSize > 0)
  4103.     {
  4104.         pDst1 = pDstRow;
  4105.         loops = 160;                // 2 pixels per loop, 320 pixels total
  4106.         bufferSize -= 640;            // consume 640 bytes of source YUV
  4107.  
  4108.         if (bufferSize)
  4109.             pDstRow = (UInt32 *) (((UInt32) pDstRow) + rowBytesRGB);
  4110.  
  4111.         // Warning - compiler (PPCC) is very sensitive about pDst1.  Masking it & 0x03
  4112.         // causes one of the two loops to be optimized into nothingness.  Sigh.
  4113.  
  4114.         // Might be faster to support double-aligned float writes
  4115.  
  4116.         pDst2 = (UInt32 *) (((UInt32) pDst1) & 0xFFFFFFFC);
  4117.         if (pDst2 == pDst1)        // pDst1 is quad-aligned, use simple loop
  4118.         {
  4119.             while (loops--)
  4120.             {
  4121.                 srcYUV = *pSrc++;
  4122.                 U = (srcYUV & 0xF8000000) >> 21;
  4123.                 V = (srcYUV & 0xF800) >> 10;
  4124.                 Y1 = (srcYUV & 0xFC0000) >> 7;
  4125.                 UV = U | V;
  4126.                 Y2 = (srcYUV & 0xFC) << 9;
  4127.  
  4128.                 // Could eliminate the << 16 by using a precomputed (table - 1) (+1?)
  4129.  
  4130.                 *pDst1++ = ((*((UInt16 *) (table + (Y1 | UV)))) << 16) |        // one pixel
  4131.                             *((UInt16 *) (table + (Y2 | UV)));                    // another
  4132.             }
  4133.         }
  4134.         else    // pDst1 is not quad-aligned (must be half-quad aligned)
  4135.         {
  4136.             srcYUV = *pSrc++;
  4137.             U = (srcYUV & 0xF8000000) >> 21;
  4138.             V = (srcYUV & 0xF800) >> 10;
  4139.             Y1 = (srcYUV & 0xFC0000) >> 7;
  4140.             UV = U | V;
  4141.             Y2 = (srcYUV & 0xFC) << 9;
  4142.  
  4143.             *((UInt16 *) pDst1) = *((UInt16 *) (table + (Y1 | UV)));        // first pixel
  4144.             hold = *((UInt16 *) (table + (Y2 | UV)));                        // next
  4145.             pDst1 = (UInt32 *) (((UInt32) pDst1) + 2);
  4146.             loops--;
  4147.  
  4148.             while (loops--)
  4149.             {
  4150.                 srcYUV = *pSrc++;
  4151.                 U = (srcYUV & 0xF8000000) >> 21;
  4152.                 V = (srcYUV & 0xF800) >> 10;
  4153.                 Y1 = (srcYUV & 0xFC0000) >> 7;
  4154.                 UV = U | V;
  4155.                 Y2 = (srcYUV & 0xFC) << 9;
  4156.                 *pDst1++ = (hold << 16) | *((UInt16 *) (table + (Y1 | UV)));
  4157.                 hold = *((UInt16 *) (table + (Y2 | UV)));
  4158.             }
  4159.  
  4160.             *((UInt16 *) pDst1)++ = hold;        // final pixel
  4161.         }
  4162.     }
  4163. }
  4164.  
  4165.  
  4166. ////////////////////////////////////////////////////////////////////////////////
  4167. //
  4168. // FWCCMConvertYUV422ToRGB16Double
  4169. //
  4170. //   This routine converts YUV 4:2:2 data to pixel-doubled 16-bit RGB data, in a
  4171. //   pixMap or similar structure.  Only whole scanlines are supported (multiple
  4172. //   scanlines will work).  If the destination is 32-bit aligned, we will use
  4173. //   64-bit writes for speed (ideally the destination is 64-bit aligned).
  4174. //   Otherwise we use 32-bit writes and performance is not quite as good.
  4175. //
  4176. //   This routine is rather optimized, and that makes it hard to read.  See the
  4177. //   comments in FWCCMConvertYUV422ToRGB32 that apply to the 320x240 case for
  4178. //   some explanation.
  4179.  
  4180. static void    FWCCMConvertYUV422ToRGB16Double(
  4181.     FWCCMVDigDataPtr            pFWCCMVDigData,
  4182.     UInt32                        *pSrcYUV,            // YUV 4:2:2 Source pointer
  4183.     UInt32                        byteCountYUV,        // Source length in bytes
  4184.     UInt32                        *pDstRGB,            // RGB 16 Destination pointer
  4185.     UInt32                        rowBytesRGB)        // Byte offset to next row of destination
  4186. {
  4187.     UInt32                        *pSrc, *pDstRow, *pDst1, *pDst2;
  4188.     UInt32                        bufferSize, loops;
  4189.     UInt32                        srcYUV, Y1, U, V, Y2, UV;
  4190.     UInt16                        hold, pix1, pix2;
  4191.     Ptr                            table;
  4192.     double                        dub;
  4193.  
  4194.     pSrc = pSrcYUV;
  4195.     pDstRow = pDstRGB;
  4196.     bufferSize = byteCountYUV;
  4197.     table = (Ptr) pFWCCMVDigData->yuvToRGB16Table;
  4198.  
  4199.     while (bufferSize > 0)
  4200.     {    
  4201.         pDst1 = pDstRow;
  4202.         loops = 160;
  4203.         bufferSize -= 640;
  4204.  
  4205.         if (bufferSize)
  4206.             pDstRow = (UInt32 *) (((UInt32) pDstRow) + rowBytesRGB);        // not likely!
  4207.  
  4208.         // Warning - compiler (PPCC) is very sensitive about pDst1.  Masking it & 0x03
  4209.         // causes one of the two loops to be optimized into nothingness.  Sigh.
  4210.  
  4211.         pDst2 = (UInt32 *) (((UInt32) pDst1) & 0xFFFFFFFC);
  4212.         if (pDst2 == pDst1)        // pDst1 is quad-aligned, use simple loop
  4213.         {
  4214.             pDst2 = (UInt32 *) (((UInt32) pDst1) + rowBytesRGB);
  4215.             while (loops--)
  4216.             {
  4217.                 srcYUV = *pSrc++;
  4218.                 U = (srcYUV & 0xF8000000) >> 21;
  4219.                 V = (srcYUV & 0xF800) >> 10;
  4220.                 Y1 = (srcYUV & 0xFC0000) >> 7;
  4221.                 UV = U | V;
  4222.                 Y2 = (srcYUV & 0xFC) << 9;
  4223.                 pix1 = *((UInt16 *) (table + (Y1 | UV)));
  4224.                 pix2 = *((UInt16 *) (table + (Y2 | UV)));
  4225.  
  4226.                 // double-writes helps, but there's room for improvement still:
  4227.  
  4228.                 *((UInt32 *) &dub) = pix1 | (pix1 << 16);
  4229.                 *((UInt32 *) (((Ptr) (&dub)) + 4)) = pix2 | (pix2 << 16);
  4230.                 *((double *) (pDst1)) = dub;
  4231.                 *((double *) (pDst2)) = dub;
  4232.                 pDst1 += 2;
  4233.                 pDst2 += 2;
  4234.             }
  4235.         }
  4236.         else    // pDst1 is not quad-aligned (must be half-quad aligned)
  4237.         {
  4238.             pDst2 = (UInt32 *) (((UInt32) pDst1) + rowBytesRGB);
  4239.             srcYUV = *pSrc++;
  4240.             U = (srcYUV & 0xF8000000) >> 21;
  4241.             V = (srcYUV & 0xF800) >> 10;
  4242.             Y1 = (srcYUV & 0xFC0000) >> 7;
  4243.             UV = U | V;
  4244.             Y2 = (srcYUV & 0xFC) << 9;
  4245.  
  4246.             // could be faster (two unaligned writes)
  4247.             hold = *((UInt16 *) (table + (Y1 | UV)));                        // first
  4248.             *pDst1++ = hold | (hold << 16);
  4249.             *pDst2++ = hold | (hold << 16);
  4250.             hold = *((UInt16 *) (table + (Y2 | UV)));                        // next
  4251.             *((UInt16 *) pDst1) = hold;    
  4252.             *((UInt16 *) pDst2) = hold;    
  4253.             pDst1 = (UInt32 *) (((UInt32) pDst1) + 2);
  4254.             pDst2 = (UInt32 *) (((UInt32) pDst2) + 2);
  4255.             loops--;
  4256.  
  4257.             while (loops--)
  4258.             {
  4259.                 srcYUV = *pSrc++;
  4260.                 U = (srcYUV & 0xF8000000) >> 21;
  4261.                 V = (srcYUV & 0xF800) >> 10;
  4262.                 Y1 = (srcYUV & 0xFC0000) >> 7;
  4263.                 UV = U | V;
  4264.                 Y2 = (srcYUV & 0xFC) << 9;
  4265.  
  4266.                 pix1 = *((UInt16 *) (table + (Y1 | UV)));
  4267.                 pix2 = *((UInt16 *) (table + (Y2 | UV)));
  4268.                 *pDst1++ = pix1 | (hold << 16);
  4269.                 *pDst2++ = pix1 | (hold << 16);
  4270.                 *pDst1++ = pix2 | (pix1 << 16);
  4271.                 *pDst2++ = pix2 | (pix1 << 16);
  4272.  
  4273.                 hold = pix2;
  4274.             }
  4275.  
  4276.             *((UInt16 *) pDst1) = hold;        // final pixel
  4277.             *((UInt16 *) pDst2) = hold;        // final pixel
  4278.         }
  4279.     }
  4280. }
  4281.  
  4282.  
  4283. ////////////////////////////////////////////////////////////////////////////////
  4284. //
  4285. // FWCCMConvertYUV422ToRGB32
  4286. //
  4287. //   This routine converts YUV 4:2:2 data into 32-bit RGB data, presumably in a
  4288. //   pixMap or similar structure.  Only whole scanlines are supported (multiple
  4289. //   scanlines will work).  We use 32-bit writes, and assume that the target will
  4290. //   be 32-bit aligned (since it is 32 bits per pixel).
  4291. //
  4292. //   This routine has slightly more comments than the others.
  4293.  
  4294. static void    FWCCMConvertYUV422ToRGB32(
  4295.     FWCCMVDigDataPtr            pFWCCMVDigData,
  4296.     UInt32                        *pSrcYUV,            // YUV 4:2:2 Source pointer
  4297.     UInt32                        byteCountYUV,        // Source length in bytes
  4298.     UInt32                        *pDstRGB,            // RGB 16 Destination pointer
  4299.     UInt32                        rowBytesRGB)        // Byte offset to next row of destination
  4300. {
  4301.     UInt32                        *pSrc, *pDstRow, *pDst1, *pDst2;
  4302.     UInt32                        bufferSize, loops;
  4303.     UInt32                        srcYUV, Y1, U, V, Y2, UV;
  4304.     Ptr                            table;
  4305.  
  4306.     pSrc = pSrcYUV;
  4307.     pDstRow = pDstRGB;
  4308.     bufferSize = byteCountYUV;
  4309.     table = (Ptr) pFWCCMVDigData->yuvToRGB32Table;
  4310.  
  4311.     while (bufferSize > 0)
  4312.     {
  4313.         pDst1 = pDstRow;
  4314.         pDst2 = pDst1 + 1;            // for pipelining
  4315.         loops = 160;                // 2 pixels per loop, 320 pixels total
  4316.         bufferSize -= 640;            // consume 640 bytes of source YUV
  4317.  
  4318.         if (bufferSize)
  4319.             pDstRow = (UInt32 *) (((UInt32) pDstRow) + rowBytesRGB);
  4320.  
  4321.         // Might be faster to support double-aligned float writes
  4322.  
  4323.         while (loops--)
  4324.         {
  4325.             // The following statements make more sense, and do the same thing,
  4326.             // but require ~60% more instructions.  (UInt8 Y, U, V, *pSrc)
  4327.             //
  4328.             //    U = pSrc[0] & 0xF8;  // 5 bits
  4329.             //    Y = pSrc[1] & 0xFC;  // 6 bits
  4330.             //    V = pSrc[2] & 0xF8;  // 5 bits
  4331.             //    *pDst++ = yuvToRGBTable[(Y << 8) | (U << 2) | (V >> 3)];
  4332.             //    Y = pSrc[3] & 0xFC;
  4333.             //    *pDst++ = yuvToRGBTable[(Y << 8) | (U << 2) | (V >> 3)];
  4334.  
  4335.             srcYUV = *pSrc++;
  4336.             U = (srcYUV & 0xF8000000) >> 20;
  4337.             V = (srcYUV & 0xF800) >> 9;
  4338.             Y1 = (srcYUV & 0xFC0000) >> 6;
  4339.             UV = U | V;
  4340.             Y2 = (srcYUV & 0xFC) << 10;
  4341.             *pDst1 = *((UInt32 *) (table + (Y1 | UV)));
  4342.             pDst1 += 2;
  4343.             *pDst2 = *((UInt32 *) (table + (Y2 | UV)));
  4344.             pDst2 += 2;
  4345.         }
  4346.     }
  4347. }
  4348.  
  4349.  
  4350. ////////////////////////////////////////////////////////////////////////////////
  4351. //
  4352. // FWCCMConvertYUV422ToRGB32Double
  4353. //
  4354. //   This routine converts YUV 4:2:2 data to pixel-doubled 32-bit RGB data, in a
  4355. //   pixMap or similar structure.  Only whole scanlines are supported (multiple
  4356. //   scanlines will work).
  4357. //
  4358. //   This routine is rather optimized, and that makes it hard to read.  See the
  4359. //   comments in FWCCMConvertYUV422ToRGB32 that apply to the 320x240 case for
  4360. //   some explanation.  We use 64-bit aligned writes regardless of target alignment.
  4361. //   Performance is best with 64-bit aligned targets.
  4362.  
  4363. static void    FWCCMConvertYUV422ToRGB32Double(
  4364.     FWCCMVDigDataPtr            pFWCCMVDigData,
  4365.     UInt32                        *pSrcYUV,            // YUV 4:2:2 Source pointer
  4366.     UInt32                        byteCountYUV,        // Source length in bytes
  4367.     UInt32                        *pDstRGB,            // RGB 16 Destination pointer
  4368.     UInt32                        rowBytesRGB)        // Byte offset to next row of destination
  4369. {
  4370.     UInt32                        *pSrc, *pDstRow, *pDst1, *pDst2;
  4371.     UInt32                        bufferSize, loops;
  4372.     UInt32                        srcYUV, Y1, U, V, Y2, UV;
  4373.     Ptr                            table;
  4374.     double                        dub;
  4375.  
  4376.     pSrc = pSrcYUV;
  4377.     pDstRow = pDstRGB;
  4378.     bufferSize = byteCountYUV;
  4379.     table = (Ptr) pFWCCMVDigData->yuvToRGB32Table;
  4380.  
  4381.     while (bufferSize > 0)
  4382.     {    
  4383.         pDst1 = pDstRow;
  4384.         pDst2 = (UInt32 *) (((UInt32) pDst1) + rowBytesRGB);
  4385.         loops = 160;
  4386.         bufferSize -= 640;
  4387.  
  4388.         if (bufferSize)
  4389.             pDstRow = (UInt32 *) (((UInt32) pDstRow) + rowBytesRGB);        // not likely!
  4390.  
  4391.         while (loops--)
  4392.         {
  4393.             srcYUV = *pSrc++;
  4394.             U = (srcYUV & 0xF8000000) >> 20;
  4395.             V = (srcYUV & 0xF800) >> 9;
  4396.             Y1 = (srcYUV & 0xFC0000) >> 6;
  4397.             UV = U | V;
  4398.             Y2 = (srcYUV & 0xFC) << 10;
  4399.  
  4400.             // double writes are a big help ... when the pixmap is double aligned.
  4401.             // they help much less when not aligned.  Fix this loop to handle both.
  4402.  
  4403.             *((UInt32 *) &dub) = *((UInt32 *) (table + (Y1 | UV)));
  4404.             *((UInt32 *) (((Ptr) (&dub)) + 4)) = *((UInt32 *) (table + (Y1 | UV)));
  4405.             *((double *) (pDst1)) = dub;
  4406.             *((double *) (pDst2)) = dub;
  4407.             pDst1 += 2;
  4408.             pDst2 += 2;
  4409.  
  4410.             *((UInt32 *) &dub) = *((UInt32 *) (table + (Y2 | UV)));
  4411.             *((UInt32 *) (((Ptr) (&dub)) + 4)) = *((UInt32 *) (table + (Y2 | UV)));
  4412.             *((double *) (pDst1)) = dub;
  4413.             *((double *) (pDst2)) = dub;
  4414.             pDst1 += 2;
  4415.             pDst2 += 2;
  4416.         }
  4417.     }
  4418. }
  4419.  
  4420.  
  4421. ////////////////////////////////////////////////////////////////////////////////
  4422. //
  4423. // FWCCMDelayForHardware
  4424. //
  4425. //   Delay for the amount of time given in duration units.
  4426. //
  4427.  
  4428. static void    FWCCMDelayForHardware(
  4429.     Duration                    duration)
  4430. {
  4431.     AbsoluteTime                absoluteDuration;
  4432.  
  4433.     absoluteDuration = DurationToAbsolute (duration);
  4434.     DelayForHardware (absoluteDuration);
  4435. }
  4436.  
  4437.  
  4438. ////////////////////////////////////////////////////////////////////////////////
  4439. //
  4440. // FWCCMClientCommandCompletionProc
  4441. //
  4442. //   This routine does generic completion of FireWire client commands that
  4443. // make asynchronous FireWire service calls.
  4444. //
  4445.  
  4446. static void    FWCCMClientCommandCompletionProc(
  4447.     FWCommandObjectID            fwCommandObjectID,
  4448.     OSStatus                    commandStatus,
  4449.     UInt32                        completionProcData)
  4450. {
  4451.     FWClientCommandIsComplete ((FWClientCommandID) completionProcData, commandStatus);
  4452. }
  4453.